diff options
Diffstat (limited to 'drivers/gpu/drm/drm_atomic.c')
-rw-r--r-- | drivers/gpu/drm/drm_atomic.c | 230 |
1 files changed, 136 insertions, 94 deletions
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index c0f336d23f9c..2fd383d7253a 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -29,7 +29,6 @@ #include <drm/drmP.h> #include <drm/drm_atomic.h> #include <drm/drm_mode.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_print.h> #include <linux/sync_file.h> @@ -188,12 +187,15 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) } for (i = 0; i < state->num_private_objs; i++) { - void *obj_state = state->private_objs[i].obj_state; + struct drm_private_obj *obj = state->private_objs[i].ptr; - state->private_objs[i].funcs->destroy_state(obj_state); - state->private_objs[i].obj = NULL; - state->private_objs[i].obj_state = NULL; - state->private_objs[i].funcs = NULL; + if (!obj) + continue; + + obj->funcs->atomic_destroy_state(obj, + state->private_objs[i].state); + state->private_objs[i].ptr = NULL; + state->private_objs[i].state = NULL; } state->num_private_objs = 0; @@ -409,34 +411,6 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, } EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc); -/** - * drm_atomic_replace_property_blob - replace a blob property - * @blob: a pointer to the member blob to be replaced - * @new_blob: the new blob to replace with - * @replaced: whether the blob has been replaced - * - * RETURNS: - * Zero on success, error code on failure - */ -static void -drm_atomic_replace_property_blob(struct drm_property_blob **blob, - struct drm_property_blob *new_blob, - bool *replaced) -{ - struct drm_property_blob *old_blob = *blob; - - if (old_blob == new_blob) - return; - - drm_property_blob_put(old_blob); - if (new_blob) - drm_property_blob_get(new_blob); - *blob = new_blob; - *replaced = true; - - return; -} - static int drm_atomic_replace_property_blob_from_id(struct drm_device *dev, struct drm_property_blob **blob, @@ -457,7 +431,7 @@ drm_atomic_replace_property_blob_from_id(struct drm_device *dev, } } - drm_atomic_replace_property_blob(blob, new_blob, replaced); + *replaced |= drm_property_replace_blob(blob, new_blob); drm_property_blob_put(new_blob); return 0; @@ -739,7 +713,7 @@ EXPORT_SYMBOL(drm_atomic_get_plane_state); * RETURNS: * Zero on success, error code on failure */ -int drm_atomic_plane_set_property(struct drm_plane *plane, +static int drm_atomic_plane_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, uint64_t val) { @@ -796,7 +770,6 @@ int drm_atomic_plane_set_property(struct drm_plane *plane, return 0; } -EXPORT_SYMBOL(drm_atomic_plane_set_property); /** * drm_atomic_plane_get_property - get property value from plane state @@ -991,11 +964,44 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, } /** + * drm_atomic_private_obj_init - initialize private object + * @obj: private object + * @state: initial private object state + * @funcs: pointer to the struct of function pointers that identify the object + * type + * + * Initialize the private object, which can be embedded into any + * driver private object that needs its own atomic state. + */ +void +drm_atomic_private_obj_init(struct drm_private_obj *obj, + struct drm_private_state *state, + const struct drm_private_state_funcs *funcs) +{ + memset(obj, 0, sizeof(*obj)); + + obj->state = state; + obj->funcs = funcs; +} +EXPORT_SYMBOL(drm_atomic_private_obj_init); + +/** + * drm_atomic_private_obj_fini - finalize private object + * @obj: private object + * + * Finalize the private object. + */ +void +drm_atomic_private_obj_fini(struct drm_private_obj *obj) +{ + obj->funcs->atomic_destroy_state(obj, obj->state); +} +EXPORT_SYMBOL(drm_atomic_private_obj_fini); + +/** * drm_atomic_get_private_obj_state - get private object state * @state: global atomic state * @obj: private object to get the state for - * @funcs: pointer to the struct of function pointers that identify the object - * type * * This function returns the private object state for the given private object, * allocating the state if needed. It does not grab any locks as the caller is @@ -1005,18 +1011,18 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, * * Either the allocated state or the error code encoded into a pointer. */ -void * -drm_atomic_get_private_obj_state(struct drm_atomic_state *state, void *obj, - const struct drm_private_state_funcs *funcs) +struct drm_private_state * +drm_atomic_get_private_obj_state(struct drm_atomic_state *state, + struct drm_private_obj *obj) { int index, num_objs, i; size_t size; struct __drm_private_objs_state *arr; + struct drm_private_state *obj_state; for (i = 0; i < state->num_private_objs; i++) - if (obj == state->private_objs[i].obj && - state->private_objs[i].obj_state) - return state->private_objs[i].obj_state; + if (obj == state->private_objs[i].ptr) + return state->private_objs[i].state; num_objs = state->num_private_objs + 1; size = sizeof(*state->private_objs) * num_objs; @@ -1028,18 +1034,21 @@ drm_atomic_get_private_obj_state(struct drm_atomic_state *state, void *obj, index = state->num_private_objs; memset(&state->private_objs[index], 0, sizeof(*state->private_objs)); - state->private_objs[index].obj_state = funcs->duplicate_state(state, obj); - if (!state->private_objs[index].obj_state) + obj_state = obj->funcs->atomic_duplicate_state(obj); + if (!obj_state) return ERR_PTR(-ENOMEM); - state->private_objs[index].obj = obj; - state->private_objs[index].funcs = funcs; + state->private_objs[index].state = obj_state; + state->private_objs[index].old_state = obj->state; + state->private_objs[index].new_state = obj_state; + state->private_objs[index].ptr = obj; + state->num_private_objs = num_objs; - DRM_DEBUG_ATOMIC("Added new private object state %p to %p\n", - state->private_objs[index].obj_state, state); + DRM_DEBUG_ATOMIC("Added new private object %p state %p to %p\n", + obj, obj_state, state); - return state->private_objs[index].obj_state; + return obj_state; } EXPORT_SYMBOL(drm_atomic_get_private_obj_state); @@ -1135,7 +1144,7 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state); * RETURNS: * Zero on success, error code on failure */ -int drm_atomic_connector_set_property(struct drm_connector *connector, +static int drm_atomic_connector_set_property(struct drm_connector *connector, struct drm_connector_state *state, struct drm_property *property, uint64_t val) { @@ -1202,7 +1211,6 @@ int drm_atomic_connector_set_property(struct drm_connector *connector, return 0; } -EXPORT_SYMBOL(drm_atomic_connector_set_property); static void drm_atomic_connector_print_state(struct drm_printer *p, const struct drm_connector_state *state) @@ -1580,38 +1588,6 @@ drm_atomic_add_affected_planes(struct drm_atomic_state *state, EXPORT_SYMBOL(drm_atomic_add_affected_planes); /** - * drm_atomic_legacy_backoff - locking backoff for legacy ioctls - * @state: atomic state - * - * This function should be used by legacy entry points which don't understand - * -EDEADLK semantics. For simplicity this one will grab all modeset locks after - * the slowpath completed. - */ -void drm_atomic_legacy_backoff(struct drm_atomic_state *state) -{ - struct drm_device *dev = state->dev; - int ret; - bool global = false; - - if (WARN_ON(dev->mode_config.acquire_ctx == state->acquire_ctx)) { - global = true; - - dev->mode_config.acquire_ctx = NULL; - } - -retry: - drm_modeset_backoff(state->acquire_ctx); - - ret = drm_modeset_lock_all_ctx(dev, state->acquire_ctx); - if (ret) - goto retry; - - if (global) - dev->mode_config.acquire_ctx = state->acquire_ctx; -} -EXPORT_SYMBOL(drm_atomic_legacy_backoff); - -/** * drm_atomic_check_only - check whether a given config would work * @state: atomic configuration to check * @@ -1655,6 +1631,9 @@ int drm_atomic_check_only(struct drm_atomic_state *state) if (config->funcs->atomic_check) ret = config->funcs->atomic_check(state->dev, state); + if (ret) + return ret; + if (!state->allow_modeset) { for_each_new_crtc_in_state(state, crtc, crtc_state, i) { if (drm_atomic_crtc_needs_modeset(crtc_state)) { @@ -1665,7 +1644,7 @@ int drm_atomic_check_only(struct drm_atomic_state *state) } } - return ret; + return 0; } EXPORT_SYMBOL(drm_atomic_check_only); @@ -1854,9 +1833,60 @@ static struct drm_pending_vblank_event *create_vblank_event( return e; } -static int atomic_set_prop(struct drm_atomic_state *state, - struct drm_mode_object *obj, struct drm_property *prop, - uint64_t prop_value) +int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state, + struct drm_connector *connector, + int mode) +{ + struct drm_connector *tmp_connector; + struct drm_connector_state *new_conn_state; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i, ret, old_mode = connector->dpms; + bool active = false; + + ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex, + state->acquire_ctx); + if (ret) + return ret; + + if (mode != DRM_MODE_DPMS_ON) + mode = DRM_MODE_DPMS_OFF; + connector->dpms = mode; + + crtc = connector->state->crtc; + if (!crtc) + goto out; + ret = drm_atomic_add_affected_connectors(state, crtc); + if (ret) + goto out; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + goto out; + } + + for_each_new_connector_in_state(state, tmp_connector, new_conn_state, i) { + if (new_conn_state->crtc != crtc) + continue; + if (tmp_connector->dpms == DRM_MODE_DPMS_ON) { + active = true; + break; + } + } + + crtc_state->active = active; + ret = drm_atomic_commit(state); +out: + if (ret != 0) + connector->dpms = old_mode; + return ret; +} + +int drm_atomic_set_property(struct drm_atomic_state *state, + struct drm_mode_object *obj, + struct drm_property *prop, + uint64_t prop_value) { struct drm_mode_object *ref; int ret; @@ -2039,7 +2069,7 @@ static int prepare_crtc_signaling(struct drm_device *dev, { struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; - int i, ret; + int i, c = 0, ret; if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) return 0; @@ -2100,8 +2130,17 @@ static int prepare_crtc_signaling(struct drm_device *dev, crtc_state->event->base.fence = fence; } + + c++; } + /* + * Having this flag means user mode pends on event which will never + * reach due to lack of at least one CRTC for signaling + */ + if (c == 0 && (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) + return -EINVAL; + return 0; } @@ -2167,10 +2206,10 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, struct drm_atomic_state *state; struct drm_modeset_acquire_ctx ctx; struct drm_plane *plane; - struct drm_out_fence_state *fence_state = NULL; + struct drm_out_fence_state *fence_state; unsigned plane_mask; int ret = 0; - unsigned int i, j, num_fences = 0; + unsigned int i, j, num_fences; /* disallow for drivers not supporting atomic: */ if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) @@ -2211,6 +2250,8 @@ retry: plane_mask = 0; copied_objs = 0; copied_props = 0; + fence_state = NULL; + num_fences = 0; for (i = 0; i < arg->count_objs; i++) { uint32_t obj_id, count_props; @@ -2267,7 +2308,8 @@ retry: goto out; } - ret = atomic_set_prop(state, obj, prop, prop_value); + ret = drm_atomic_set_property(state, obj, prop, + prop_value); if (ret) { drm_mode_object_put(obj); goto out; |