drm/atomic: Add current-mode blob to CRTC state
Add a blob property tracking the current mode to the CRTC state, and ensure it is properly updated and referenced. v2: Continue using crtc_state->mode inside getcrtc, instead of reading out the mode blob. Use IS_ERR and PTR_ERR from create_blob. Move set_mode_prop_for_crtc to later patch where it actually gets used. Enforce !!state->enable == !!state->mode_blob inside drm_atomic_crtc_check. Signed-off-by: Daniel Stone <daniels@collabora.com> Tested-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
parent
819364da20
commit
99cf4a29fa
3 changed files with 40 additions and 6 deletions
|
@ -304,11 +304,25 @@ EXPORT_SYMBOL(drm_atomic_get_crtc_state);
|
||||||
int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
|
int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
|
||||||
struct drm_display_mode *mode)
|
struct drm_display_mode *mode)
|
||||||
{
|
{
|
||||||
|
struct drm_mode_modeinfo umode;
|
||||||
|
|
||||||
/* Early return for no change. */
|
/* Early return for no change. */
|
||||||
if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0)
|
if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (state->mode_blob)
|
||||||
|
drm_property_unreference_blob(state->mode_blob);
|
||||||
|
state->mode_blob = NULL;
|
||||||
|
|
||||||
if (mode) {
|
if (mode) {
|
||||||
|
drm_mode_convert_to_umode(&umode, mode);
|
||||||
|
state->mode_blob =
|
||||||
|
drm_property_create_blob(state->crtc->dev,
|
||||||
|
sizeof(umode),
|
||||||
|
&umode);
|
||||||
|
if (IS_ERR(state->mode_blob))
|
||||||
|
return PTR_ERR(state->mode_blob);
|
||||||
|
|
||||||
drm_mode_copy(&state->mode, mode);
|
drm_mode_copy(&state->mode, mode);
|
||||||
state->enable = true;
|
state->enable = true;
|
||||||
DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n",
|
DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n",
|
||||||
|
@ -324,7 +338,6 @@ int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc);
|
EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* drm_atomic_crtc_set_property - set property on CRTC
|
* drm_atomic_crtc_set_property - set property on CRTC
|
||||||
* @crtc: the drm CRTC to set a property on
|
* @crtc: the drm CRTC to set a property on
|
||||||
|
@ -410,6 +423,23 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The state->enable vs. state->mode_blob checks can be WARN_ON,
|
||||||
|
* as this is a kernel-internal detail that userspace should never
|
||||||
|
* be able to trigger. */
|
||||||
|
if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) &&
|
||||||
|
WARN_ON(state->enable && !state->mode_blob)) {
|
||||||
|
DRM_DEBUG_ATOMIC("[CRTC:%d] enabled without mode blob\n",
|
||||||
|
crtc->base.id);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) &&
|
||||||
|
WARN_ON(!state->enable && state->mode_blob)) {
|
||||||
|
DRM_DEBUG_ATOMIC("[CRTC:%d] disabled with mode blob\n",
|
||||||
|
crtc->base.id);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2044,6 +2044,8 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_dpms);
|
||||||
*/
|
*/
|
||||||
void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
|
void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
|
||||||
{
|
{
|
||||||
|
if (crtc->state && crtc->state->mode_blob)
|
||||||
|
drm_property_unreference_blob(crtc->state->mode_blob);
|
||||||
kfree(crtc->state);
|
kfree(crtc->state);
|
||||||
crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
|
crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
|
||||||
|
|
||||||
|
@ -2065,6 +2067,8 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
|
||||||
{
|
{
|
||||||
memcpy(state, crtc->state, sizeof(*state));
|
memcpy(state, crtc->state, sizeof(*state));
|
||||||
|
|
||||||
|
if (state->mode_blob)
|
||||||
|
drm_property_reference_blob(state->mode_blob);
|
||||||
state->mode_changed = false;
|
state->mode_changed = false;
|
||||||
state->active_changed = false;
|
state->active_changed = false;
|
||||||
state->planes_changed = false;
|
state->planes_changed = false;
|
||||||
|
@ -2107,11 +2111,8 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
|
||||||
void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
|
void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
|
||||||
struct drm_crtc_state *state)
|
struct drm_crtc_state *state)
|
||||||
{
|
{
|
||||||
/*
|
if (state->mode_blob)
|
||||||
* This is currently a placeholder so that drivers that subclass the
|
drm_property_unreference_blob(state->mode_blob);
|
||||||
* state will automatically do the right thing if code is ever added
|
|
||||||
* to this function.
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
|
EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
|
||||||
|
|
||||||
|
|
|
@ -299,6 +299,9 @@ struct drm_crtc_state {
|
||||||
|
|
||||||
struct drm_display_mode mode;
|
struct drm_display_mode mode;
|
||||||
|
|
||||||
|
/* blob property to expose current mode to atomic userspace */
|
||||||
|
struct drm_property_blob *mode_blob;
|
||||||
|
|
||||||
struct drm_pending_vblank_event *event;
|
struct drm_pending_vblank_event *event;
|
||||||
|
|
||||||
struct drm_atomic_state *state;
|
struct drm_atomic_state *state;
|
||||||
|
|
Loading…
Add table
Reference in a new issue