summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/drm_atomic.c32
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c11
-rw-r--r--include/drm/drm_crtc.h3
3 files changed, 40 insertions, 6 deletions
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index e749287390a3..327ccc71012f 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 e69d4847e237..a900858fa265 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 72b60dbe0891..c54fa4add792 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;