Commit da20eabd authored by Maarten Lankhorst's avatar Maarten Lankhorst Committed by Daniel Vetter

drm/i915: Split plane updates of crtc->atomic into a helper, v2.

This makes it easier to verify that no changes are done when
calling this from crtc instead.

Changes since v1:
 - Make intel_wm_need_update static and always check it.
Signed-off-by: default avatarMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reviewed-by: default avatarMatt Roper <matthew.d.roper@intel.com>
Tested-by(IVB): Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 86adf9d7
......@@ -114,6 +114,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane,
struct intel_crtc_state *crtc_state;
struct intel_plane *intel_plane = to_intel_plane(plane);
struct intel_plane_state *intel_state = to_intel_plane_state(state);
int ret;
crtc = crtc ? crtc : plane->crtc;
intel_crtc = to_intel_crtc(crtc);
......@@ -160,20 +161,6 @@ static int intel_plane_atomic_check(struct drm_plane *plane,
intel_state->clip.y2 =
crtc_state->base.active ? crtc_state->pipe_src_h : 0;
/*
* Disabling a plane is always okay; we just need to update
* fb tracking in a special way since cleanup_fb() won't
* get called by the plane helpers.
*/
if (state->fb == NULL && plane->state->fb != NULL) {
/*
* 'prepare' is never called when plane is being disabled, so
* we need to handle frontbuffer tracking as a special case
*/
intel_crtc->atomic.disabled_planes |=
(1 << drm_plane_index(plane));
}
if (state->fb && intel_rotation_90_or_270(state->rotation)) {
if (!(state->fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
state->fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED)) {
......@@ -198,7 +185,11 @@ static int intel_plane_atomic_check(struct drm_plane *plane,
}
}
return intel_plane->check_plane(plane, intel_state);
ret = intel_plane->check_plane(plane, intel_state);
if (ret || !state->state)
return ret;
return intel_plane_atomic_calc_changes(&crtc_state->base, state);
}
static void intel_plane_atomic_update(struct drm_plane *plane,
......
......@@ -4403,19 +4403,19 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state, int force_detach)
* skl_update_scaler_plane - Stages update to scaler state for a given plane.
*
* @state: crtc's scaler state
* @intel_plane: affected plane
* @plane_state: atomic plane state to update
*
* Return
* 0 - scaler_usage updated successfully
* error - requested scaling cannot be supported or other error condition
*/
int skl_update_scaler_plane(struct intel_crtc_state *crtc_state,
struct intel_plane *intel_plane,
struct intel_plane_state *plane_state)
static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
struct intel_plane *intel_plane =
to_intel_plane(plane_state->base.plane);
struct drm_framebuffer *fb = plane_state->base.fb;
int ret;
......@@ -11677,6 +11677,161 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
return ret;
}
/**
* intel_wm_need_update - Check whether watermarks need updating
* @plane: drm plane
* @state: new plane state
*
* Check current plane state versus the new one to determine whether
* watermarks need to be recalculated.
*
* Returns true or false.
*/
static bool intel_wm_need_update(struct drm_plane *plane,
struct drm_plane_state *state)
{
/* Update watermarks on tiling changes. */
if (!plane->state->fb || !state->fb ||
plane->state->fb->modifier[0] != state->fb->modifier[0] ||
plane->state->rotation != state->rotation)
return true;
if (plane->state->crtc_w != state->crtc_w)
return true;
return false;
}
int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
struct drm_plane_state *plane_state)
{
struct drm_crtc *crtc = crtc_state->crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct drm_plane *plane = plane_state->plane;
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_plane_state *old_plane_state =
to_intel_plane_state(plane->state);
int idx = intel_crtc->base.base.id, ret;
int i = drm_plane_index(plane);
bool mode_changed = needs_modeset(crtc_state);
bool was_crtc_enabled = crtc->state->active;
bool is_crtc_enabled = crtc_state->active;
bool turn_off, turn_on, visible, was_visible;
struct drm_framebuffer *fb = plane_state->fb;
if (crtc_state && INTEL_INFO(dev)->gen >= 9 &&
plane->type != DRM_PLANE_TYPE_CURSOR) {
ret = skl_update_scaler_plane(
to_intel_crtc_state(crtc_state),
to_intel_plane_state(plane_state));
if (ret)
return ret;
}
/*
* Disabling a plane is always okay; we just need to update
* fb tracking in a special way since cleanup_fb() won't
* get called by the plane helpers.
*/
if (old_plane_state->base.fb && !fb)
intel_crtc->atomic.disabled_planes |= 1 << i;
/* don't run rest during modeset yet */
if (!intel_crtc->active || mode_changed)
return 0;
was_visible = old_plane_state->visible;
visible = to_intel_plane_state(plane_state)->visible;
if (!was_crtc_enabled && WARN_ON(was_visible))
was_visible = false;
if (!is_crtc_enabled && WARN_ON(visible))
visible = false;
if (!was_visible && !visible)
return 0;
turn_off = was_visible && (!visible || mode_changed);
turn_on = visible && (!was_visible || mode_changed);
DRM_DEBUG_ATOMIC("[CRTC:%i] has [PLANE:%i] with fb %i\n", idx,
plane->base.id, fb ? fb->base.id : -1);
DRM_DEBUG_ATOMIC("[PLANE:%i] visible %i -> %i, off %i, on %i, ms %i\n",
plane->base.id, was_visible, visible,
turn_off, turn_on, mode_changed);
if (intel_wm_need_update(plane, plane_state))
intel_crtc->atomic.update_wm = true;
switch (plane->type) {
case DRM_PLANE_TYPE_PRIMARY:
if (visible)
intel_crtc->atomic.fb_bits |=
INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe);
intel_crtc->atomic.wait_for_flips = true;
intel_crtc->atomic.pre_disable_primary = turn_off;
intel_crtc->atomic.post_enable_primary = turn_on;
if (turn_off)
intel_crtc->atomic.disable_fbc = 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 (visible &&
INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
dev_priv->fbc.crtc == intel_crtc &&
plane_state->rotation != BIT(DRM_ROTATE_0))
intel_crtc->atomic.disable_fbc = true;
/*
* 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 (turn_on && IS_BROADWELL(dev))
intel_crtc->atomic.wait_vblank = true;
intel_crtc->atomic.update_fbc |= visible || mode_changed;
break;
case DRM_PLANE_TYPE_CURSOR:
if (visible)
intel_crtc->atomic.fb_bits |=
INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe);
break;
case DRM_PLANE_TYPE_OVERLAY:
/*
* 'prepare' is never called when plane is being disabled, so
* we need to handle frontbuffer tracking as a special case
*/
if (visible)
intel_crtc->atomic.fb_bits |=
INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe);
if (turn_off && is_crtc_enabled) {
intel_crtc->atomic.wait_vblank = true;
intel_crtc->atomic.update_sprite_watermarks |=
1 << i;
}
break;
}
return 0;
}
static bool encoders_cloneable(const struct intel_encoder *a,
const struct intel_encoder *b)
{
......@@ -13443,28 +13598,6 @@ static void intel_shared_dpll_init(struct drm_device *dev)
BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
}
/**
* intel_wm_need_update - Check whether watermarks need updating
* @plane: drm plane
* @state: new plane state
*
* Check current plane state versus the new one to determine whether
* watermarks need to be recalculated.
*
* Returns true or false.
*/
bool intel_wm_need_update(struct drm_plane *plane,
struct drm_plane_state *state)
{
/* Update watermarks on tiling changes. */
if (!plane->state->fb || !state->fb ||
plane->state->fb->modifier[0] != state->fb->modifier[0] ||
plane->state->rotation != state->rotation)
return true;
return false;
}
/**
* intel_prepare_plane_fb - Prepare fb for usage on plane
* @plane: drm plane to prepare for
......@@ -13586,7 +13719,6 @@ 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;
struct intel_crtc_state *crtc_state;
......@@ -13597,7 +13729,6 @@ intel_check_primary_plane(struct drm_plane *plane,
bool can_position = false;
int max_scale = DRM_PLANE_HELPER_NO_SCALING;
int min_scale = DRM_PLANE_HELPER_NO_SCALING;
int ret;
crtc = crtc ? crtc : plane->crtc;
intel_crtc = to_intel_crtc(crtc);
......@@ -13613,73 +13744,11 @@ intel_check_primary_plane(struct drm_plane *plane,
can_position = true;
}
ret = drm_plane_helper_check_update(plane, crtc, fb,
src, dest, clip,
min_scale,
max_scale,
can_position, true,
&state->visible);
if (ret)
return ret;
if (intel_crtc->active) {
struct intel_plane_state *old_state =
to_intel_plane_state(plane->state);
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 (state->visible &&
INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
dev_priv->fbc.crtc == intel_crtc &&
state->base.rotation != BIT(DRM_ROTATE_0)) {
intel_crtc->atomic.disable_fbc = true;
}
if (state->visible && !old_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->atomic.wait_vblank = true;
if (crtc_state && !needs_modeset(&crtc_state->base))
intel_crtc->atomic.post_enable_primary = true;
}
if (!state->visible && old_state->visible &&
crtc_state && !needs_modeset(&crtc_state->base))
intel_crtc->atomic.pre_disable_primary = true;
intel_crtc->atomic.fb_bits |=
INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe);
intel_crtc->atomic.update_fbc = true;
if (intel_wm_need_update(plane, &state->base))
intel_crtc->atomic.update_wm = true;
}
if (INTEL_INFO(dev)->gen >= 9) {
ret = skl_update_scaler_plane(crtc_state,
to_intel_plane(plane),
state);
if (ret)
return ret;
}
return 0;
return drm_plane_helper_check_update(plane, crtc, fb,
src, dest, clip,
min_scale, max_scale,
can_position, true,
&state->visible);
}
static void
......@@ -13939,10 +14008,9 @@ intel_check_cursor_plane(struct drm_plane *plane,
if (ret)
return ret;
/* if we want to turn off the cursor ignore width and height */
if (!obj)
goto finish;
return 0;
/* Check for which cursor types we support */
if (!cursor_size_ok(dev, state->base.crtc_w, state->base.crtc_h)) {
......@@ -13959,19 +14027,10 @@ intel_check_cursor_plane(struct drm_plane *plane,
if (fb->modifier[0] != DRM_FORMAT_MOD_NONE) {
DRM_DEBUG_KMS("cursor cannot be tiled\n");
ret = -EINVAL;
}
finish:
if (intel_crtc->active) {
if (plane->state->crtc_w != state->base.crtc_w)
intel_crtc->atomic.update_wm = true;
intel_crtc->atomic.fb_bits |=
INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe);
return -EINVAL;
}
return ret;
return 0;
}
static void
......
......@@ -1067,6 +1067,8 @@ int intel_plane_atomic_set_property(struct drm_plane *plane,
struct drm_plane_state *state,
struct drm_property *property,
uint64_t val);
int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
struct drm_plane_state *plane_state);
unsigned int
intel_tile_height(struct drm_device *dev, uint32_t pixel_format,
......@@ -1081,9 +1083,6 @@ intel_rotation_90_or_270(unsigned int rotation)
void intel_create_rotation_property(struct drm_device *dev,
struct intel_plane *plane);
bool intel_wm_need_update(struct drm_plane *plane,
struct drm_plane_state *state);
/* shared dpll functions */
struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
void assert_shared_dpll(struct drm_i915_private *dev_priv,
......@@ -1148,9 +1147,6 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode,
void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc);
void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file);
void skl_detach_scalers(struct intel_crtc *intel_crtc);
int skl_update_scaler_plane(struct intel_crtc_state *crtc_state,
struct intel_plane *intel_plane,
struct intel_plane_state *plane_state);
int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state, int force_detach);
int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state);
......
......@@ -759,7 +759,6 @@ intel_check_sprite_plane(struct drm_plane *plane,
int max_scale, min_scale;
bool can_scale;
int pixel_size;
int ret;
intel_crtc = intel_crtc ? intel_crtc : to_intel_crtc(plane->crtc);
crtc_state = state->base.state ?
......@@ -767,7 +766,7 @@ intel_check_sprite_plane(struct drm_plane *plane,
if (!fb) {
state->visible = false;
goto finish;
return 0;
}
/* Don't modify another pipe's plane */
......@@ -920,35 +919,6 @@ intel_check_sprite_plane(struct drm_plane *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.
*/
if (intel_crtc->active) {
intel_crtc->atomic.fb_bits |=
INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe);
if (intel_wm_need_update(plane, &state->base))
intel_crtc->atomic.update_wm = true;
if (!state->visible) {
/*
* Avoid underruns when disabling the sprite.
* FIXME remove once watermark updates are done properly.
*/
intel_crtc->atomic.wait_vblank = true;
intel_crtc->atomic.update_sprite_watermarks |=
(1 << drm_plane_index(plane));
}
}
if (INTEL_INFO(dev)->gen >= 9) {
ret = skl_update_scaler_plane(crtc_state, intel_plane, state);
if (ret)
return ret;
}
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment