1
0
Fork 0
mirror of synced 2025-03-06 20:59:54 +01:00
linux/drivers/gpu/drm/i915/display/intel_sprite_uapi.c
Ville Syrjälä 76ec692721 drm/i915: Flag purely internal commits to not clear crtc_state->inherited
If we have to force the hardware to go through a full modeset
due to eg. cdclk reprogramming, we need to preserve
crtc_state->inherited for all crtcs that have not otherwise
gone through the whole compute_config() stuff after connectors
have been detected.

Otherwise eg. cdclk induced modeset glk_force_audio_cdclk()
will clear the inherited flag, and thus the first real commit
coming from userspace later on will not be forced through
the full .compute_config() path and so eg. audio state may
not get properly recomputed.

But instead of adding all kinds of ad-hoc crtc_state->inherited
preservation hacks all over, let's change things so that we
only clear it for the crtcs directly included in userspace/client
initiated commits.

Should be far less fragile since now we just need to remember
to flag the internal commits, and not worry about where new
crtcs might get pulled in.

Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/5260
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230328122357.1697-1-ville.syrjala@linux.intel.com
Reviewed-by: Luca Coelho <luciano.coelho@intel.com>
2023-04-13 14:22:42 +03:00

128 lines
3.4 KiB
C

// SPDX-License-Identifier: MIT
/*
* Copyright © 2023 Intel Corporation
*/
#include "i915_drv.h"
#include "intel_crtc.h"
#include "intel_display_types.h"
#include "intel_sprite_uapi.h"
static bool has_dst_key_in_primary_plane(struct drm_i915_private *dev_priv)
{
return DISPLAY_VER(dev_priv) >= 9;
}
static void intel_plane_set_ckey(struct intel_plane_state *plane_state,
const struct drm_intel_sprite_colorkey *set)
{
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
*key = *set;
/*
* We want src key enabled on the
* sprite and not on the primary.
*/
if (plane->id == PLANE_PRIMARY &&
set->flags & I915_SET_COLORKEY_SOURCE)
key->flags = 0;
/*
* On SKL+ we want dst key enabled on
* the primary and not on the sprite.
*/
if (DISPLAY_VER(dev_priv) >= 9 && plane->id != PLANE_PRIMARY &&
set->flags & I915_SET_COLORKEY_DESTINATION)
key->flags = 0;
}
int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_i915_private *dev_priv = to_i915(dev);
struct drm_intel_sprite_colorkey *set = data;
struct drm_plane *plane;
struct drm_plane_state *plane_state;
struct drm_atomic_state *state;
struct drm_modeset_acquire_ctx ctx;
int ret = 0;
/* ignore the pointless "none" flag */
set->flags &= ~I915_SET_COLORKEY_NONE;
if (set->flags & ~(I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
return -EINVAL;
/* Make sure we don't try to enable both src & dest simultaneously */
if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
return -EINVAL;
if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
set->flags & I915_SET_COLORKEY_DESTINATION)
return -EINVAL;
plane = drm_plane_find(dev, file_priv, set->plane_id);
if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY)
return -ENOENT;
/*
* SKL+ only plane 2 can do destination keying against plane 1.
* Also multiple planes can't do destination keying on the same
* pipe simultaneously.
*/
if (DISPLAY_VER(dev_priv) >= 9 &&
to_intel_plane(plane)->id >= PLANE_SPRITE1 &&
set->flags & I915_SET_COLORKEY_DESTINATION)
return -EINVAL;
drm_modeset_acquire_init(&ctx, 0);
state = drm_atomic_state_alloc(plane->dev);
if (!state) {
ret = -ENOMEM;
goto out;
}
state->acquire_ctx = &ctx;
to_intel_atomic_state(state)->internal = true;
while (1) {
plane_state = drm_atomic_get_plane_state(state, plane);
ret = PTR_ERR_OR_ZERO(plane_state);
if (!ret)
intel_plane_set_ckey(to_intel_plane_state(plane_state), set);
/*
* On some platforms we have to configure
* the dst colorkey on the primary plane.
*/
if (!ret && has_dst_key_in_primary_plane(dev_priv)) {
struct intel_crtc *crtc =
intel_crtc_for_pipe(dev_priv,
to_intel_plane(plane)->pipe);
plane_state = drm_atomic_get_plane_state(state,
crtc->base.primary);
ret = PTR_ERR_OR_ZERO(plane_state);
if (!ret)
intel_plane_set_ckey(to_intel_plane_state(plane_state), set);
}
if (!ret)
ret = drm_atomic_commit(state);
if (ret != -EDEADLK)
break;
drm_atomic_state_clear(state);
drm_modeset_backoff(&ctx);
}
drm_atomic_state_put(state);
out:
drm_modeset_drop_locks(&ctx);
drm_modeset_acquire_fini(&ctx);
return ret;
}