Hi, Respin with the fixups from Daniel Vetter's review. The two changes visible to userspace is that we now require anyone clearing MODE_ID to explicitly set the CRTC active property to false, and that the property type is BLOB, rather than OBJECT/BLOB.
The rest are fairly minor.
Cheers, Daniel
When we look up a blob property, make sure we retain a reference to the blob for the lifetime.
v2: Use DRM_MODE_PROP_BLOB, not PROP_OBJECT + OBJECT_BLOB.
Signed-off-by: Daniel Stone daniels@collabora.com Tested-by: Sean Paul seanpaul@chromium.org --- drivers/gpu/drm/drm_crtc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index e548c50..2de6edf 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4775,7 +4775,8 @@ void drm_property_change_valid_put(struct drm_property *property, if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { if (property->values[0] == DRM_MODE_OBJECT_FB) drm_framebuffer_unreference(obj_to_fb(ref)); - } + } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) + drm_property_unreference_blob(obj_to_blob(ref)); }
/**
Add a new helper, to be used later for blob property management, that sets the mode for a CRTC state, as well as updating the CRTC enable/active state at the same time.
v2: Do not touch active/mode_changed in CRTC state. Document return value. Remove stray drm_atomic_set_mode_prop_for_crtc declaration.
Signed-off-by: Daniel Stone daniels@collabora.com Tested-by: Sean Paul seanpaul@chromium.org --- drivers/gpu/drm/drm_atomic.c | 36 +++++++++++++++++++++++++ drivers/gpu/drm/drm_atomic_helper.c | 11 +++++--- drivers/gpu/drm/drm_crtc_helper.c | 5 ++-- drivers/gpu/drm/i915/intel_display.c | 51 ++++++++++++++++++++++++++---------- include/drm/drm_atomic.h | 3 +++ 5 files changed, 87 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 3134f50..e749287 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -290,6 +290,42 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, EXPORT_SYMBOL(drm_atomic_get_crtc_state);
/** + * drm_atomic_set_mode_for_crtc - set mode for CRTC + * @state: the CRTC whose incoming state to update + * @mode: kernel-internal mode to use for the CRTC, or NULL to disable + * + * Set a mode (originating from the kernel) on the desired CRTC state. Does + * not change any other state properties, including enable, active, or + * mode_changed. + * + * RETURNS: + * Zero on success, error code on failure. Cannot return -EDEADLK. + */ +int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, + struct drm_display_mode *mode) +{ + /* Early return for no change. */ + if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0) + return 0; + + if (mode) { + drm_mode_copy(&state->mode, mode); + state->enable = true; + DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n", + mode->name, state); + } else { + memset(&state->mode, 0, sizeof(state->mode)); + state->enable = false; + DRM_DEBUG_ATOMIC("Set [NOMODE] for CRTC state %p\n", + state); + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc); + + +/** * drm_atomic_crtc_set_property - set property on CRTC * @crtc: the drm CRTC to set a property on * @state: the state object to update with the new property value diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index a64bacd..e69d484 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1607,7 +1607,10 @@ retry: WARN_ON(set->fb); WARN_ON(set->num_connectors);
- crtc_state->enable = false; + ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); + if (ret != 0) + goto fail; + crtc_state->active = false;
ret = drm_atomic_set_crtc_for_plane(primary_state, NULL); @@ -1622,9 +1625,11 @@ retry: WARN_ON(!set->fb); WARN_ON(!set->num_connectors);
- crtc_state->enable = true; + ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode); + if (ret != 0) + goto fail; + crtc_state->active = true; - drm_mode_copy(&crtc_state->mode, set->mode);
ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); if (ret != 0) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 9297a61..393114d 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -937,10 +937,11 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod crtc_state->crtc = crtc; }
- crtc_state->enable = true; crtc_state->planes_changed = true; crtc_state->mode_changed = true; - drm_mode_copy(&crtc_state->mode, mode); + ret = drm_atomic_set_mode_for_crtc(crtc_state, mode); + if (ret) + goto out; drm_mode_copy(&crtc_state->adjusted_mode, adjusted_mode);
if (crtc_funcs->atomic_check) { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 240092a..d085c81 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9896,7 +9896,9 @@ retry: if (ret) goto fail;
- drm_mode_copy(&crtc_state->base.mode, mode); + ret = drm_atomic_set_mode_for_crtc(&crtc_state->base, mode); + if (ret) + goto fail;
if (intel_set_mode(crtc, state)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); @@ -12481,9 +12483,6 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) }
for_each_intel_crtc(dev, intel_crtc) { - if (intel_crtc->new_enabled == intel_crtc->base.enabled) - continue; - crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); if (IS_ERR(crtc_state)) { DRM_DEBUG_KMS("Failed to add [CRTC:%d] to state: %ld\n", @@ -12492,10 +12491,15 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) continue; }
- crtc_state->base.enable = intel_crtc->new_enabled; - - if (&intel_crtc->base == crtc) - drm_mode_copy(&crtc_state->base.mode, &crtc->mode); + if (!intel_crtc->new_enabled) { + ret = drm_atomic_set_mode_for_crtc(&crtc_state->base, + NULL); + WARN_ON(ret); + } else if (&intel_crtc->base == crtc) { + ret = drm_atomic_set_mode_for_crtc(&crtc_state->base, + &crtc->mode); + WARN_ON(ret); + } }
intel_modeset_setup_plane_state(state, crtc, &crtc->mode, @@ -12617,11 +12621,23 @@ intel_modeset_stage_output_state(struct drm_device *dev, }
for_each_crtc_in_state(state, crtc, crtc_state, i) { + bool has_connectors; + ret = drm_atomic_add_affected_connectors(state, crtc); if (ret) return ret;
- crtc_state->enable = drm_atomic_connectors_for_crtc(state, crtc); + has_connectors = drm_atomic_connectors_for_crtc(state, crtc); + + if (!has_connectors) { + ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); + if (ret) + return ret; + } else if (crtc == set->crtc) { + ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode); + if (ret) + return ret; + } }
ret = intel_modeset_setup_plane_state(state, set->crtc, set->mode, @@ -12633,9 +12649,6 @@ intel_modeset_stage_output_state(struct drm_device *dev, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state);
- if (set->mode) - drm_mode_copy(&crtc_state->mode, set->mode); - if (set->num_connectors) crtc_state->active = true;
@@ -14544,6 +14557,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + int ret; u32 reg;
/* Clear any frame start delays used for debugging left by the BIOS */ @@ -14594,7 +14608,8 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) }
WARN_ON(crtc->active); - crtc->base.state->enable = false; + ret = drm_atomic_set_mode_for_crtc(crtc->base.state, NULL); + WARN_ON(ret); crtc->base.enabled = false; }
@@ -14622,7 +14637,15 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) crtc->base.state->enable ? "enabled" : "disabled", crtc->active ? "enabled" : "disabled");
- crtc->base.state->enable = crtc->active; + if (crtc->active) { + ret = drm_atomic_set_mode_for_crtc(crtc->base.state, + &crtc->base.mode); + WARN_ON(ret); + } else { + ret = drm_atomic_set_mode_for_crtc(crtc->base.state, + NULL); + WARN_ON(ret); + } crtc->base.enabled = crtc->active;
/* Because we only establish the connector -> encoder -> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index e89db0c..1e8c61f 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -110,6 +110,9 @@ drm_atomic_get_existing_connector_state(struct drm_atomic_state *state, }
int __must_check +drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, + struct drm_display_mode *mode); +int __must_check drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, struct drm_crtc *crtc); void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
Add a new helper, to be used later for blob property management, that sets the mode for a CRTC state, as well as updating the CRTC enable/active state at the same time.
v2: Do not touch active/mode_changed in CRTC state. Document return value. Remove stray drm_atomic_set_mode_prop_for_crtc declaration.
v3: Remove i915 changes, and leave it directly bashing crtc_state->mode for the meantime.
Signed-off-by: Daniel Stone daniels@collabora.com Tested-by: Sean Paul seanpaul@chromium.org --- drivers/gpu/drm/drm_atomic.c | 36 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_atomic_helper.c | 11 ++++++++--- drivers/gpu/drm/drm_crtc_helper.c | 5 +++-- include/drm/drm_atomic.h | 3 +++ 4 files changed, 50 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 3134f50..e749287 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -290,6 +290,42 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, EXPORT_SYMBOL(drm_atomic_get_crtc_state);
/** + * drm_atomic_set_mode_for_crtc - set mode for CRTC + * @state: the CRTC whose incoming state to update + * @mode: kernel-internal mode to use for the CRTC, or NULL to disable + * + * Set a mode (originating from the kernel) on the desired CRTC state. Does + * not change any other state properties, including enable, active, or + * mode_changed. + * + * RETURNS: + * Zero on success, error code on failure. Cannot return -EDEADLK. + */ +int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, + struct drm_display_mode *mode) +{ + /* Early return for no change. */ + if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0) + return 0; + + if (mode) { + drm_mode_copy(&state->mode, mode); + state->enable = true; + DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n", + mode->name, state); + } else { + memset(&state->mode, 0, sizeof(state->mode)); + state->enable = false; + DRM_DEBUG_ATOMIC("Set [NOMODE] for CRTC state %p\n", + state); + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc); + + +/** * drm_atomic_crtc_set_property - set property on CRTC * @crtc: the drm CRTC to set a property on * @state: the state object to update with the new property value diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index a64bacd..e69d484 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1607,7 +1607,10 @@ retry: WARN_ON(set->fb); WARN_ON(set->num_connectors);
- crtc_state->enable = false; + ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); + if (ret != 0) + goto fail; + crtc_state->active = false;
ret = drm_atomic_set_crtc_for_plane(primary_state, NULL); @@ -1622,9 +1625,11 @@ retry: WARN_ON(!set->fb); WARN_ON(!set->num_connectors);
- crtc_state->enable = true; + ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode); + if (ret != 0) + goto fail; + crtc_state->active = true; - drm_mode_copy(&crtc_state->mode, set->mode);
ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); if (ret != 0) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 9297a61..393114d 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -937,10 +937,11 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod crtc_state->crtc = crtc; }
- crtc_state->enable = true; crtc_state->planes_changed = true; crtc_state->mode_changed = true; - drm_mode_copy(&crtc_state->mode, mode); + ret = drm_atomic_set_mode_for_crtc(crtc_state, mode); + if (ret) + goto out; drm_mode_copy(&crtc_state->adjusted_mode, adjusted_mode);
if (crtc_funcs->atomic_check) { diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index e89db0c..1e8c61f 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -110,6 +110,9 @@ drm_atomic_get_existing_connector_state(struct drm_atomic_state *state, }
int __must_check +drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, + struct drm_display_mode *mode); +int __must_check drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, struct drm_crtc *crtc); void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
On Tue, May 26, 2015 at 02:36:48PM +0100, Daniel Stone wrote:
Add a new helper, to be used later for blob property management, that sets the mode for a CRTC state, as well as updating the CRTC enable/active state at the same time.
v2: Do not touch active/mode_changed in CRTC state. Document return value. Remove stray drm_atomic_set_mode_prop_for_crtc declaration.
v3: Remove i915 changes, and leave it directly bashing crtc_state->mode for the meantime.
Signed-off-by: Daniel Stone daniels@collabora.com Tested-by: Sean Paul seanpaul@chromium.org
Pulled in all the patches from this series, thanks. -Daniel
drivers/gpu/drm/drm_atomic.c | 36 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_atomic_helper.c | 11 ++++++++--- drivers/gpu/drm/drm_crtc_helper.c | 5 +++-- include/drm/drm_atomic.h | 3 +++ 4 files changed, 50 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 3134f50..e749287 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -290,6 +290,42 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, EXPORT_SYMBOL(drm_atomic_get_crtc_state);
/**
- drm_atomic_set_mode_for_crtc - set mode for CRTC
- @state: the CRTC whose incoming state to update
- @mode: kernel-internal mode to use for the CRTC, or NULL to disable
- Set a mode (originating from the kernel) on the desired CRTC state. Does
- not change any other state properties, including enable, active, or
- mode_changed.
- RETURNS:
- Zero on success, error code on failure. Cannot return -EDEADLK.
- */
+int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
struct drm_display_mode *mode)
+{
- /* Early return for no change. */
- if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0)
return 0;
- if (mode) {
drm_mode_copy(&state->mode, mode);
state->enable = true;
DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n",
mode->name, state);
- } else {
memset(&state->mode, 0, sizeof(state->mode));
state->enable = false;
DRM_DEBUG_ATOMIC("Set [NOMODE] for CRTC state %p\n",
state);
- }
- return 0;
+} +EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc);
+/**
- drm_atomic_crtc_set_property - set property on CRTC
- @crtc: the drm CRTC to set a property on
- @state: the state object to update with the new property value
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index a64bacd..e69d484 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1607,7 +1607,10 @@ retry: WARN_ON(set->fb); WARN_ON(set->num_connectors);
crtc_state->enable = false;
ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
if (ret != 0)
goto fail;
crtc_state->active = false;
ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
@@ -1622,9 +1625,11 @@ retry: WARN_ON(!set->fb); WARN_ON(!set->num_connectors);
- crtc_state->enable = true;
- ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
- if (ret != 0)
goto fail;
- crtc_state->active = true;
drm_mode_copy(&crtc_state->mode, set->mode);
ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); if (ret != 0)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 9297a61..393114d 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -937,10 +937,11 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod crtc_state->crtc = crtc; }
- crtc_state->enable = true; crtc_state->planes_changed = true; crtc_state->mode_changed = true;
- drm_mode_copy(&crtc_state->mode, mode);
ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
if (ret)
goto out;
drm_mode_copy(&crtc_state->adjusted_mode, adjusted_mode);
if (crtc_funcs->atomic_check) {
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index e89db0c..1e8c61f 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -110,6 +110,9 @@ drm_atomic_get_existing_connector_state(struct drm_atomic_state *state, }
int __must_check +drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
struct drm_display_mode *mode);
+int __must_check drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, struct drm_crtc *crtc); void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, -- 2.4.1
dri-devel mailing list dri-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel
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 --- drivers/gpu/drm/drm_atomic.c | 32 +++++++++++++++++++++++++++++++- drivers/gpu/drm/drm_atomic_helper.c | 11 ++++++----- include/drm/drm_crtc.h | 3 +++ 3 files changed, 40 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index e749287..327ccc7 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -304,11 +304,25 @@ EXPORT_SYMBOL(drm_atomic_get_crtc_state); int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, struct drm_display_mode *mode) { + struct drm_mode_modeinfo umode; + /* Early return for no change. */ if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0) return 0;
+ if (state->mode_blob) + drm_property_unreference_blob(state->mode_blob); + state->mode_blob = NULL; + 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); state->enable = true; 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);
- /** * drm_atomic_crtc_set_property - set property on CRTC * @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; }
+ /* 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; }
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index e69d484..a900858 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2044,6 +2044,8 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_dpms); */ 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); 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));
+ if (state->mode_blob) + drm_property_reference_blob(state->mode_blob); state->mode_changed = false; state->active_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, struct drm_crtc_state *state) { - /* - * This is currently a placeholder so that drivers that subclass the - * state will automatically do the right thing if code is ever added - * to this function. - */ + if (state->mode_blob) + drm_property_unreference_blob(state->mode_blob); } EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 72b60db..c54fa4a 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -299,6 +299,9 @@ struct drm_crtc_state {
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_atomic_state *state;
Atomic modesetting: now with modesetting support.
v2: Moved drm_atomic_set_mode_prop_for_crtc from previous patch; removed state->active fiddling, documented return code. Changed property type to DRM_MODE_PROP_BLOB.
Signed-off-by: Daniel Stone daniels@collabora.com Tested-by: Sean Paul seanpaul@chromium.org --- drivers/gpu/drm/drm_atomic.c | 57 +++++++++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/drm_crtc.c | 8 +++++++ include/drm/drm_atomic.h | 3 +++ include/drm/drm_crtc.h | 1 + 4 files changed, 68 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 327ccc7..c7e59b0 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -339,6 +339,51 @@ int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc);
/** + * drm_atomic_set_mode_prop_for_crtc - set mode for CRTC + * @state: the CRTC whose incoming state to update + * @blob: pointer to blob property to use for mode + * + * Set a mode (originating from a blob property) on the desired CRTC state. + * This function will take a reference on the blob property for the CRTC state, + * and release the reference held on the state's existing mode property, if any + * was set. + * + * RETURNS: + * Zero on success, error code on failure. Cannot return -EDEADLK. + */ +int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, + struct drm_property_blob *blob) +{ + if (blob == state->mode_blob) + return 0; + + if (state->mode_blob) + drm_property_unreference_blob(state->mode_blob); + state->mode_blob = NULL; + + if (blob) { + if (blob->length != sizeof(struct drm_mode_modeinfo) || + drm_mode_convert_umode(&state->mode, + (const struct drm_mode_modeinfo *) + blob->data)) + return -EINVAL; + + state->mode_blob = drm_property_reference_blob(blob); + state->enable = true; + DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n", + state->mode.name, state); + } else { + memset(&state->mode, 0, sizeof(state->mode)); + state->enable = false; + DRM_DEBUG_ATOMIC("Set [NOMODE] for CRTC state %p\n", + state); + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc); + +/** * drm_atomic_crtc_set_property - set property on CRTC * @crtc: the drm CRTC to set a property on * @state: the state object to update with the new property value @@ -360,10 +405,18 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct drm_mode_config *config = &dev->mode_config; + int ret;
- /* FIXME: Mode prop is missing, which also controls ->enable. */ if (property == config->prop_active) state->active = val; + else if (property == config->prop_mode_id) { + struct drm_property_blob *mode = + drm_property_lookup_blob(dev, val); + ret = drm_atomic_set_mode_prop_for_crtc(state, mode); + if (mode) + drm_property_unreference_blob(mode); + return ret; + } else if (crtc->funcs->atomic_set_property) return crtc->funcs->atomic_set_property(crtc, state, property, val); else @@ -388,6 +441,8 @@ int drm_atomic_crtc_get_property(struct drm_crtc *crtc,
if (property == config->prop_active) *val = state->active; + else if (property == config->prop_mode_id) + *val = (state->mode_blob) ? state->mode_blob->base.id : 0; else if (crtc->funcs->atomic_get_property) return crtc->funcs->atomic_get_property(crtc, state, property, val); else diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 2de6edf..b4b365c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -688,6 +688,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { drm_object_attach_property(&crtc->base, config->prop_active, 0); + drm_object_attach_property(&crtc->base, config->prop_mode_id, 0); }
return 0; @@ -1454,6 +1455,13 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) return -ENOMEM; dev->mode_config.prop_active = prop;
+ prop = drm_property_create(dev, + DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB, + "MODE_ID", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_mode_id = prop; + return 0; }
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 1e8c61f..55f4604 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -113,6 +113,9 @@ int __must_check drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, struct drm_display_mode *mode); int __must_check +drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, + struct drm_property_blob *blob); +int __must_check drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, struct drm_crtc *crtc); void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index c54fa4a..3b4d8a4 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1146,6 +1146,7 @@ struct drm_mode_config { struct drm_property *prop_fb_id; struct drm_property *prop_crtc_id; struct drm_property *prop_active; + struct drm_property *prop_mode_id;
/* DVI-I properties */ struct drm_property *dvi_i_subconnector_property;
dri-devel@lists.freedesktop.org