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@xxxxxxxxxxxxx> Tested-by: Sean Paul <seanpaul@xxxxxxxxxxxx> --- 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, -- 2.4.1 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel