[RFCv2 10/13] drm: convert plane to properties/state
Matt Roper
matthew.d.roper at intel.com
Thu Oct 24 23:48:11 CEST 2013
On Mon, Oct 14, 2013 at 01:26:45PM -0400, Rob Clark wrote:
> Break the mutable state of a plane out into a separate structure
> and use atomic properties mechanism to set plane attributes. This
> makes it easier to have some helpers for plane->set_property()
> and for checking for invalid params. The idea is that individual
> drivers can wrap the state struct in their own struct which adds
> driver specific parameters, for easy build-up of state across
> multiple set_property() calls and for easy atomic commit or roll-
> back.
>
> The same should be done for CRTC, encoder, and connector, but this
> patch only includes the first part (plane).
> ---
> drivers/gpu/drm/drm_atomic_helper.c | 137 +++++++++-
> drivers/gpu/drm/drm_crtc.c | 399 +++++++++++++++++++---------
> drivers/gpu/drm/drm_fb_helper.c | 17 +-
> drivers/gpu/drm/exynos/exynos_drm_crtc.c | 4 +-
> drivers/gpu/drm/exynos/exynos_drm_encoder.c | 6 +-
> drivers/gpu/drm/exynos/exynos_drm_plane.c | 13 +-
> drivers/gpu/drm/i915/intel_sprite.c | 19 +-
> drivers/gpu/drm/msm/mdp4/mdp4_crtc.c | 2 +-
> drivers/gpu/drm/msm/mdp4/mdp4_plane.c | 18 +-
> drivers/gpu/drm/omapdrm/omap_crtc.c | 4 +-
> drivers/gpu/drm/omapdrm/omap_drv.c | 2 +-
> drivers/gpu/drm/omapdrm/omap_plane.c | 30 ++-
> drivers/gpu/drm/rcar-du/rcar_du_plane.c | 5 +-
> drivers/gpu/drm/shmobile/shmob_drm_crtc.c | 2 +-
> drivers/gpu/drm/shmobile/shmob_drm_plane.c | 6 +-
> drivers/gpu/host1x/drm/dc.c | 16 +-
> include/drm/drm_atomic_helper.h | 37 ++-
> include/drm/drm_crtc.h | 88 +++++-
> 18 files changed, 615 insertions(+), 190 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 46c67b8..0618113 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -39,10 +39,12 @@
> void *drm_atomic_helper_begin(struct drm_device *dev, uint32_t flags)
> {
> struct drm_atomic_helper_state *state;
> + int nplanes = dev->mode_config.num_plane;
> int sz;
> void *ptr;
>
> sz = sizeof(*state);
> + sz += (sizeof(state->planes) + sizeof(state->pstates)) * nplanes;
>
> ptr = kzalloc(sz, GFP_KERNEL);
>
> @@ -52,6 +54,13 @@ void *drm_atomic_helper_begin(struct drm_device *dev, uint32_t flags)
> kref_init(&state->refcount);
> state->dev = dev;
> state->flags = flags;
> +
> + state->planes = ptr;
> + ptr = &state->planes[nplanes];
> +
> + state->pstates = ptr;
> + ptr = &state->pstates[nplanes];
> +
> return state;
> }
> EXPORT_SYMBOL(drm_atomic_helper_begin);
> @@ -87,7 +96,19 @@ EXPORT_SYMBOL(drm_atomic_helper_set_event);
> */
> int drm_atomic_helper_check(struct drm_device *dev, void *state)
> {
> - return 0; /* for now */
> + struct drm_atomic_helper_state *a = state;
> + int nplanes = dev->mode_config.num_plane;
> + int i, ret = 0;
> +
> + for (i = 0; i < nplanes; i++) {
> + if (a->planes[i]) {
> + ret = drm_atomic_check_plane_state(a->planes[i], a->pstates[i]);
> + if (ret)
> + break;
> + }
> + }
> +
> + return ret;
> }
> EXPORT_SYMBOL(drm_atomic_helper_check);
>
> @@ -104,7 +125,19 @@ EXPORT_SYMBOL(drm_atomic_helper_check);
> */
> int drm_atomic_helper_commit(struct drm_device *dev, void *state)
> {
> - return 0; /* for now */
> + struct drm_atomic_helper_state *a = state;
> + int nplanes = dev->mode_config.num_plane;
> + int i, ret = 0;
> +
> + for (i = 0; i < nplanes; i++) {
> + if (a->planes[i]) {
> + ret = drm_atomic_commit_plane_state(a->planes[i], a->pstates[i]);
> + if (ret)
> + break;
> + }
> + }
> +
> + return ret;
> }
> EXPORT_SYMBOL(drm_atomic_helper_commit);
>
> @@ -125,11 +158,111 @@ void _drm_atomic_helper_state_free(struct kref *kref)
> {
> struct drm_atomic_helper_state *state =
> container_of(kref, struct drm_atomic_helper_state, refcount);
> + struct drm_device *dev = state->dev;
> + int nplanes = dev->mode_config.num_plane;
> + int i;
> +
> + for (i = 0; i < nplanes; i++) {
> + if (state->pstates[i]) {
> + state->planes[i]->state->state = NULL;
> + kfree(state->pstates[i]);
> + }
> + }
> +
> kfree(state);
> }
> EXPORT_SYMBOL(_drm_atomic_helper_state_free);
>
> +int drm_atomic_helper_plane_set_property(struct drm_plane *plane, void *state,
> + struct drm_property *property, uint64_t val, void *blob_data)
> +{
> + return drm_plane_set_property(plane,
> + drm_atomic_get_plane_state(plane, state),
> + property, val, blob_data);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_plane_set_property);
> +
> +void drm_atomic_helper_init_plane_state(struct drm_plane *plane,
> + struct drm_plane_state *pstate, void *state)
> +{
> + /* snapshot current state: */
> + *pstate = *plane->state;
> + pstate->state = state;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_init_plane_state);
> +
> +static struct drm_plane_state *
> +drm_atomic_helper_get_plane_state(struct drm_plane *plane, void *state)
> +{
> + struct drm_atomic_helper_state *a = state;
> + struct drm_plane_state *pstate = a->pstates[plane->id];
> + if (!pstate) {
> + pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
> + drm_atomic_helper_init_plane_state(plane, pstate, state);
> + a->planes[plane->id] = plane;
> + a->pstates[plane->id] = pstate;
> + }
> + return pstate;
> +}
> +
> +static void
> +swap_plane_state(struct drm_plane *plane, struct drm_atomic_helper_state *a)
> +{
> + swap(plane->state, a->pstates[plane->id]);
> + plane->base.propvals = &plane->state->propvals;
> +}
> +
> +static int
> +drm_atomic_helper_commit_plane_state(struct drm_plane *plane,
> + struct drm_plane_state *pstate)
> +{
> + struct drm_device *dev = plane->dev;
> + struct drm_framebuffer *old_fb = NULL, *fb = NULL;
> + int ret = 0;
> +
> + /* probably more fine grain locking would be ok of old crtc
> + * and new crtc were same..
> + */
> + drm_modeset_lock_all(dev);
> +
> + fb = pstate->fb;
> +
> + if (pstate->crtc && fb) {
> + ret = plane->funcs->update_plane(plane, pstate->crtc, pstate->fb,
> + pstate->crtc_x, pstate->crtc_y, pstate->crtc_w, pstate->crtc_h,
> + pstate->src_x, pstate->src_y, pstate->src_w, pstate->src_h);
> + if (!ret) {
> + /* on success, update state and fb refcnting: */
> + /* NOTE: if we ensure no driver sets plane->state->fb = NULL
> + * on disable, we can move this up a level and not duplicate
> + * nearly the same thing for both update_plane and disable_plane
> + * cases.. I leave it like this for now to be paranoid due to
> + * the slightly different ordering in the two cases in the
> + * original code.
> + */
> + old_fb = plane->state->fb;
> + swap_plane_state(plane, pstate->state);
> + fb = NULL;
> + }
> + } else {
> + old_fb = plane->state->fb;
> + plane->funcs->disable_plane(plane);
> + swap_plane_state(plane, pstate->state);
> + }
> +
> + drm_modeset_unlock_all(dev);
> +
> + if (fb)
> + drm_framebuffer_unreference(fb);
> + if (old_fb)
> + drm_framebuffer_unreference(old_fb);
> +
> + return ret;
> +}
>
> const struct drm_atomic_helper_funcs drm_atomic_helper_funcs = {
> + .get_plane_state = drm_atomic_helper_get_plane_state,
> + .check_plane_state = drm_plane_check_state,
> + .commit_plane_state = drm_atomic_helper_commit_plane_state,
> };
> EXPORT_SYMBOL(drm_atomic_helper_funcs);
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 9f46f3b..3cf235e 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -595,7 +595,20 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
> * in this manner.
> */
> if (atomic_read(&fb->refcount.refcount) > 1) {
> + void *state;
> +
> + state = dev->driver->atomic_begin(dev, 0);
> + if (IS_ERR(state)) {
> + DRM_ERROR("failed to disable crtc and/or plane when fb was deleted\n");
> + return;
> + }
> +
> + /* TODO once CRTC is converted to state/properties, we can push the
> + * locking down into drm_atomic_helper_commit(), since that is where
> + * the actual changes take place..
> + */
> drm_modeset_lock_all(dev);
> +
> /* remove from any CRTC */
> list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> if (crtc->fb == fb) {
> @@ -610,9 +623,18 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
> }
>
> list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> - if (plane->fb == fb)
> - drm_plane_force_disable(plane);
> + if (plane->state->fb == fb)
> + drm_plane_force_disable(plane, state);
> }
> +
> + /* just disabling stuff shouldn't fail, hopefully: */
> + if(dev->driver->atomic_check(dev, state))
> + DRM_ERROR("failed to disable crtc and/or plane when fb was deleted\n");
> + else
> + dev->driver->atomic_commit(dev, state);
> +
> + dev->driver->atomic_end(dev, state);
> +
> drm_modeset_unlock_all(dev);
> }
>
> @@ -904,8 +926,12 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
> const uint32_t *formats, uint32_t format_count,
> bool priv)
> {
> + struct drm_mode_config *config = &dev->mode_config;
> int ret;
>
> + if (!plane->state)
> + plane->state = kzalloc(sizeof(plane->state), GFP_KERNEL);
> +
> drm_modeset_lock_all(dev);
>
> ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
> @@ -913,7 +939,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
> goto out;
>
> plane->base.properties = &plane->properties;
> - plane->base.propvals = &plane->propvals;
> + plane->base.propvals = &plane->state->propvals;
> plane->dev = dev;
> plane->funcs = funcs;
> plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
> @@ -935,11 +961,23 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
> */
> if (!priv) {
> list_add_tail(&plane->head, &dev->mode_config.plane_list);
> + plane->id = dev->mode_config.num_plane;
> dev->mode_config.num_plane++;
> } else {
> INIT_LIST_HEAD(&plane->head);
> }
>
> + drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
> + drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
> + drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
> + drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
> + drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
> + drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
> + drm_object_attach_property(&plane->base, config->prop_src_x, 0);
> + drm_object_attach_property(&plane->base, config->prop_src_y, 0);
> + drm_object_attach_property(&plane->base, config->prop_src_w, 0);
> + drm_object_attach_property(&plane->base, config->prop_src_h, 0);
> +
> out:
> drm_modeset_unlock_all(dev);
>
> @@ -971,6 +1009,111 @@ void drm_plane_cleanup(struct drm_plane *plane)
> }
> EXPORT_SYMBOL(drm_plane_cleanup);
>
> +int drm_plane_check_state(struct drm_plane *plane,
> + struct drm_plane_state *state)
> +{
> + unsigned int fb_width, fb_height;
> + struct drm_framebuffer *fb = state->fb;
> + int i;
> +
> + /* disabling the plane is allowed: */
> + if (!fb)
> + return 0;
> +
> + fb_width = fb->width << 16;
> + fb_height = fb->height << 16;
> +
> + /* Check whether this plane supports the fb pixel format. */
> + for (i = 0; i < plane->format_count; i++)
> + if (fb->pixel_format == plane->format_types[i])
> + break;
> + if (i == plane->format_count) {
> + DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format);
> + return -EINVAL;
> + }
> +
> + /* Make sure source coordinates are inside the fb. */
> + if (state->src_w > fb_width ||
> + state->src_x > fb_width - state->src_w ||
> + state->src_h > fb_height ||
> + state->src_y > fb_height - state->src_h) {
> + DRM_DEBUG_KMS("Invalid source coordinates "
> + "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
> + state->src_w >> 16,
> + ((state->src_w & 0xffff) * 15625) >> 10,
> + state->src_h >> 16,
> + ((state->src_h & 0xffff) * 15625) >> 10,
> + state->src_x >> 16,
> + ((state->src_x & 0xffff) * 15625) >> 10,
> + state->src_y >> 16,
> + ((state->src_y & 0xffff) * 15625) >> 10);
> + return -ENOSPC;
> + }
> +
> + /* Give drivers some help against integer overflows */
> + if (state->crtc_w > INT_MAX ||
> + state->crtc_x > INT_MAX - (int32_t) state->crtc_w ||
> + state->crtc_h > INT_MAX ||
> + state->crtc_y > INT_MAX - (int32_t) state->crtc_h) {
> + DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
> + state->crtc_w, state->crtc_h,
> + state->crtc_x, state->crtc_y);
> + return -ERANGE;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_plane_check_state);
> +
> +void drm_plane_commit_state(struct drm_plane *plane,
> + struct drm_plane_state *state)
> +{
> + plane->state = state;
> + plane->base.propvals = &state->propvals;
> +}
> +EXPORT_SYMBOL(drm_plane_commit_state);
> +
> +int drm_plane_set_property(struct drm_plane *plane,
> + struct drm_plane_state *state,
> + struct drm_property *property,
> + uint64_t value, void *blob_data)
> +{
> + struct drm_device *dev = plane->dev;
> + struct drm_mode_config *config = &dev->mode_config;
> +
> + drm_object_property_set_value(&plane->base,
> + &state->propvals, property, value, blob_data);
> +
> + if (property == config->prop_fb_id) {
> + state->new_fb = true;
> + state->fb = drm_framebuffer_lookup(dev, value);
> + } else if (property == config->prop_crtc_id) {
> + struct drm_mode_object *obj = drm_property_get_obj(property, value);
> + state->crtc = obj ? obj_to_crtc(obj) : NULL;
> + } else if (property == config->prop_crtc_x) {
> + state->crtc_x = U642I64(value);
> + } else if (property == config->prop_crtc_y) {
> + state->crtc_y = U642I64(value);
> + } else if (property == config->prop_crtc_w) {
> + state->crtc_w = value;
> + } else if (property == config->prop_crtc_h) {
> + state->crtc_h = value;
> + } else if (property == config->prop_src_x) {
> + state->src_x = value;
> + } else if (property == config->prop_src_y) {
> + state->src_y = value;
> + } else if (property == config->prop_src_w) {
> + state->src_w = value;
> + } else if (property == config->prop_src_h) {
> + state->src_h = value;
> + } else {
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_plane_set_property);
> +
> /**
> * drm_plane_force_disable - Forcibly disable a plane
> * @plane: plane to disable
> @@ -980,20 +1123,15 @@ EXPORT_SYMBOL(drm_plane_cleanup);
> * Used when the plane's current framebuffer is destroyed,
> * and when restoring fbdev mode.
> */
> -void drm_plane_force_disable(struct drm_plane *plane)
> +void drm_plane_force_disable(struct drm_plane *plane, void *state)
> {
> - int ret;
> + struct drm_mode_config *config = &plane->dev->mode_config;
>
> - if (!plane->fb)
> - return;
> -
> - ret = plane->funcs->disable_plane(plane);
> - if (ret)
> - DRM_ERROR("failed to disable plane with busy fb\n");
> - /* disconnect the plane from the fb and crtc: */
> - __drm_framebuffer_unreference(plane->fb);
> - plane->fb = NULL;
> - plane->crtc = NULL;
> + /* should turn off the crtc */
> + drm_mode_plane_set_obj_prop(plane, state,
> + config->prop_crtc_id, 0, NULL);
> + drm_mode_plane_set_obj_prop(plane, state,
> + config->prop_fb_id, 0, NULL);
> }
> EXPORT_SYMBOL(drm_plane_force_disable);
>
> @@ -1043,21 +1181,89 @@ EXPORT_SYMBOL(drm_mode_destroy);
>
> static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
> {
> - struct drm_property *edid;
> - struct drm_property *dpms;
> + struct drm_property *prop;
>
> /*
> * Standard properties (apply to all connectors)
> */
> - edid = drm_property_create(dev, DRM_MODE_PROP_BLOB |
> + prop = drm_property_create(dev, DRM_MODE_PROP_BLOB |
> DRM_MODE_PROP_IMMUTABLE,
> "EDID", 0);
> - dev->mode_config.edid_property = edid;
> + if (!prop)
> + return -ENOMEM;
> + dev->mode_config.edid_property = prop;
>
> - dpms = drm_property_create_enum(dev, 0,
> + prop = drm_property_create_enum(dev, 0,
> "DPMS", drm_dpms_enum_list,
> ARRAY_SIZE(drm_dpms_enum_list));
> - dev->mode_config.dpms_property = dpms;
> + if (!prop)
> + return -ENOMEM;
> + dev->mode_config.dpms_property = prop;
> +
> +
> + /* TODO we need the driver to control which of these are dynamic
> + * and which are not.. or maybe we should just set all to zero
> + * and let the individual drivers frob the prop->flags for the
> + * properties they can support dynamic changes on..
> + */
> +
> + prop = drm_property_create_range(dev, DRM_MODE_PROP_DYNAMIC,
> + "SRC_X", 0, UINT_MAX);
> + if (!prop)
> + return -ENOMEM;
> + dev->mode_config.prop_src_x = prop;
> +
> + prop = drm_property_create_range(dev, DRM_MODE_PROP_DYNAMIC,
> + "SRC_Y", 0, UINT_MAX);
> + if (!prop)
> + return -ENOMEM;
> + dev->mode_config.prop_src_y = prop;
> +
> + prop = drm_property_create_range(dev, 0, "SRC_W", 0, UINT_MAX);
> + if (!prop)
> + return -ENOMEM;
> + dev->mode_config.prop_src_w = prop;
> +
> + prop = drm_property_create_range(dev, 0, "SRC_H", 0, UINT_MAX);
> + if (!prop)
> + return -ENOMEM;
> + dev->mode_config.prop_src_h = prop;
> +
> + prop = drm_property_create_range(dev,
> + DRM_MODE_PROP_DYNAMIC | DRM_MODE_PROP_SIGNED,
> + "CRTC_X", I642U64(INT_MIN), I642U64(INT_MAX));
> + if (!prop)
> + return -ENOMEM;
> + dev->mode_config.prop_crtc_x = prop;
> +
> + prop = drm_property_create_range(dev,
> + DRM_MODE_PROP_DYNAMIC | DRM_MODE_PROP_SIGNED,
> + "CRTC_Y", I642U64(INT_MIN), I642U64(INT_MAX));
> + if (!prop)
> + return -ENOMEM;
> + dev->mode_config.prop_crtc_y = prop;
> +
> + prop = drm_property_create_range(dev, 0, "CRTC_W", 0, INT_MAX);
> + if (!prop)
> + return -ENOMEM;
> + dev->mode_config.prop_crtc_w = prop;
> +
> + prop = drm_property_create_range(dev, 0, "CRTC_H", 0, INT_MAX);
> + if (!prop)
> + return -ENOMEM;
> + dev->mode_config.prop_crtc_h = prop;
> +
> + prop = drm_property_create_object(dev, DRM_MODE_PROP_DYNAMIC,
> + "FB_ID", DRM_MODE_OBJECT_FB);
> + if (!prop)
> + return -ENOMEM;
> + dev->mode_config.prop_fb_id = prop;
> +
> + prop = drm_property_create_object(dev, 0,
> + "CRTC_ID", DRM_MODE_OBJECT_CRTC);
> + if (!prop)
> + return -ENOMEM;
> + dev->mode_config.prop_crtc_id = prop;
>
> return 0;
> }
> @@ -1842,13 +2048,13 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
> }
> plane = obj_to_plane(obj);
>
> - if (plane->crtc)
> - plane_resp->crtc_id = plane->crtc->base.id;
> + if (plane->state->crtc)
> + plane_resp->crtc_id = plane->state->crtc->base.id;
> else
> plane_resp->crtc_id = 0;
>
> - if (plane->fb)
> - plane_resp->fb_id = plane->fb->base.id;
> + if (plane->state->fb)
> + plane_resp->fb_id = plane->state->fb->base.id;
> else
> plane_resp->fb_id = 0;
>
> @@ -1890,21 +2096,18 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
> struct drm_file *file_priv)
> {
> struct drm_mode_set_plane *plane_req = data;
> + struct drm_mode_config *config = &dev->mode_config;
> struct drm_mode_object *obj;
> - struct drm_plane *plane;
> - struct drm_crtc *crtc;
> - struct drm_framebuffer *fb = NULL, *old_fb = NULL;
> + void *state;
> int ret = 0;
> - unsigned int fb_width, fb_height;
> - int i;
>
> if (!drm_core_check_feature(dev, DRIVER_MODESET))
> return -EINVAL;
>
> - /*
> - * First, find the plane, crtc, and fb objects. If not available,
> - * we don't bother to call the driver.
> - */
> + state = dev->driver->atomic_begin(dev, 0);
> + if (IS_ERR(state))
> + return PTR_ERR(state);
> +
> obj = drm_mode_object_find(dev, plane_req->plane_id,
> DRM_MODE_OBJECT_PLANE);
> if (!obj) {
> @@ -1912,102 +2115,36 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
> plane_req->plane_id);
> return -ENOENT;
> }
> - plane = obj_to_plane(obj);
> -
> - /* No fb means shut it down */
> - if (!plane_req->fb_id) {
> - drm_modeset_lock_all(dev);
> - old_fb = plane->fb;
> - plane->funcs->disable_plane(plane);
> - plane->crtc = NULL;
> - plane->fb = NULL;
> - drm_modeset_unlock_all(dev);
> - goto out;
> - }
>
> - obj = drm_mode_object_find(dev, plane_req->crtc_id,
> - DRM_MODE_OBJECT_CRTC);
> - if (!obj) {
> - DRM_DEBUG_KMS("Unknown crtc ID %d\n",
> - plane_req->crtc_id);
> - ret = -ENOENT;
> - goto out;
> - }
> - crtc = obj_to_crtc(obj);
> -
> - fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
> - if (!fb) {
> - DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
> - plane_req->fb_id);
> - ret = -ENOENT;
> - goto out;
> - }
> -
> - /* Check whether this plane supports the fb pixel format. */
> - for (i = 0; i < plane->format_count; i++)
> - if (fb->pixel_format == plane->format_types[i])
> - break;
> - if (i == plane->format_count) {
> - DRM_DEBUG_KMS("Invalid pixel format %s\n",
> - drm_get_format_name(fb->pixel_format));
> - ret = -EINVAL;
> - goto out;
> - }
> -
> - fb_width = fb->width << 16;
> - fb_height = fb->height << 16;
> -
> - /* Make sure source coordinates are inside the fb. */
> - if (plane_req->src_w > fb_width ||
> - plane_req->src_x > fb_width - plane_req->src_w ||
> - plane_req->src_h > fb_height ||
> - plane_req->src_y > fb_height - plane_req->src_h) {
> - DRM_DEBUG_KMS("Invalid source coordinates "
> - "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
> - plane_req->src_w >> 16,
> - ((plane_req->src_w & 0xffff) * 15625) >> 10,
> - plane_req->src_h >> 16,
> - ((plane_req->src_h & 0xffff) * 15625) >> 10,
> - plane_req->src_x >> 16,
> - ((plane_req->src_x & 0xffff) * 15625) >> 10,
> - plane_req->src_y >> 16,
> - ((plane_req->src_y & 0xffff) * 15625) >> 10);
> - ret = -ENOSPC;
> - goto out;
> - }
> -
> - /* Give drivers some help against integer overflows */
> - if (plane_req->crtc_w > INT_MAX ||
> - plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
> - plane_req->crtc_h > INT_MAX ||
> - plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
> - DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
> - plane_req->crtc_w, plane_req->crtc_h,
> - plane_req->crtc_x, plane_req->crtc_y);
> - ret = -ERANGE;
> + ret =
> + drm_mode_set_obj_prop(obj, state,
> + config->prop_crtc_id, plane_req->crtc_id, NULL) ||
> + drm_mode_set_obj_prop(obj, state,
> + config->prop_fb_id, plane_req->fb_id, NULL) ||
> + drm_mode_set_obj_prop(obj, state,
> + config->prop_crtc_x, I642U64(plane_req->crtc_x), NULL) ||
> + drm_mode_set_obj_prop(obj, state,
> + config->prop_crtc_y, I642U64(plane_req->crtc_y), NULL) ||
> + drm_mode_set_obj_prop(obj, state,
> + config->prop_crtc_w, plane_req->crtc_w, NULL) ||
> + drm_mode_set_obj_prop(obj, state,
> + config->prop_crtc_h, plane_req->crtc_h, NULL) ||
> + drm_mode_set_obj_prop(obj, state,
> + config->prop_src_w, plane_req->src_w, NULL) ||
> + drm_mode_set_obj_prop(obj, state,
> + config->prop_src_h, plane_req->src_h, NULL) ||
> + drm_mode_set_obj_prop(obj, state,
> + config->prop_src_x, plane_req->src_x, NULL) ||
> + drm_mode_set_obj_prop(obj, state,
> + config->prop_src_y, plane_req->src_y, NULL) ||
> + dev->driver->atomic_check(dev, state);
> + if (ret)
> goto out;
> - }
>
> - drm_modeset_lock_all(dev);
> - ret = plane->funcs->update_plane(plane, crtc, fb,
> - plane_req->crtc_x, plane_req->crtc_y,
> - plane_req->crtc_w, plane_req->crtc_h,
> - plane_req->src_x, plane_req->src_y,
> - plane_req->src_w, plane_req->src_h);
> - if (!ret) {
> - old_fb = plane->fb;
> - plane->crtc = crtc;
> - plane->fb = fb;
> - fb = NULL;
> - }
> - drm_modeset_unlock_all(dev);
> + ret = dev->driver->atomic_commit(dev, state);
>
> out:
> - if (fb)
> - drm_framebuffer_unreference(fb);
> - if (old_fb)
> - drm_framebuffer_unreference(old_fb);
> -
> + dev->driver->atomic_end(dev, state);
> return ret;
> }
>
> @@ -3296,7 +3433,7 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
> return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
> }
>
> -static int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
> +int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
> void *state, struct drm_property *property,
> uint64_t value, void *blob_data)
> {
> @@ -3319,8 +3456,9 @@ static int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
>
> return ret;
> }
> +EXPORT_SYMBOL(drm_mode_connector_set_obj_prop);
>
> -static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
> +int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
> void *state, struct drm_property *property,
> uint64_t value, void *blob_data)
> {
> @@ -3335,8 +3473,9 @@ static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
>
> return ret;
> }
> +EXPORT_SYMBOL(drm_mode_crtc_set_obj_prop);
>
> -static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
> +int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
> void *state, struct drm_property *property,
> uint64_t value, void *blob_data)
> {
> @@ -3345,12 +3484,10 @@ static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
> if (plane->funcs->set_property)
> ret = plane->funcs->set_property(plane, state, property,
> value, blob_data);
> - if (!ret)
> - drm_object_property_set_value(&plane->base, &plane->propvals,
> - property, value, NULL);
>
> return ret;
> }
> +EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
>
> static int drm_mode_set_obj_prop(struct drm_mode_object *obj,
> void *state, struct drm_property *property,
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 24898dc..f1fc605 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -290,12 +290,27 @@ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
> struct drm_device *dev = fb_helper->dev;
> struct drm_plane *plane;
> bool error = false;
> + void *state;
> int i;
>
> drm_warn_on_modeset_not_all_locked(dev);
>
> + state = dev->driver->atomic_begin(dev, 0);
> + if (IS_ERR(state)) {
> + DRM_ERROR("failed to restore fbdev mode\n");
> + return true;
> + }
> +
> list_for_each_entry(plane, &dev->mode_config.plane_list, head)
> - drm_plane_force_disable(plane);
> + drm_plane_force_disable(plane, state);
> +
> + /* just disabling stuff shouldn't fail, hopefully: */
> + if(dev->driver->atomic_check(dev, state))
> + DRM_ERROR("failed to restore fbdev mode\n");
> + else
> + dev->driver->atomic_commit(dev, state);
I'm seeing some deadlocks here on i915 when we trigger the lastclose
handler. We're already holding mode_config.mutex when we enter this
function, but drm_atomic_helper_commit_plane_state does another
drm_modeset_lock_all() call.
Matt
> +
> + dev->driver->atomic_end(dev, state);
>
> for (i = 0; i < fb_helper->crtc_count; i++) {
> struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> index 82a9fca..4ae55b8 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> @@ -124,8 +124,8 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
> if (ret)
> return ret;
>
> - plane->crtc = crtc;
> - plane->fb = crtc->fb;
> + plane->state->crtc = crtc;
> + plane->state->fb = crtc->fb;
>
> exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe);
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> index 06f1b2a..dbe2e19 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> @@ -127,7 +127,7 @@ static void disable_plane_to_crtc(struct drm_device *dev,
> * (encoder->crtc)
> */
> list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> - if (plane->crtc == old_crtc) {
> + if (plane->state->crtc == old_crtc) {
> /*
> * do not change below call order.
> *
> @@ -138,7 +138,7 @@ static void disable_plane_to_crtc(struct drm_device *dev,
> * have new_crtc because new_crtc was set to
> * encoder->crtc in advance.
> */
> - plane->crtc = new_crtc;
> + plane->state->crtc = new_crtc;
> plane->funcs->disable_plane(plane);
> }
> }
> @@ -247,7 +247,7 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
>
> /* all planes connected to this encoder should be also disabled. */
> list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> - if (plane->crtc == encoder->crtc)
> + if (plane->state->crtc == encoder->crtc)
> plane->funcs->disable_plane(plane);
> }
> }
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
> index 2e31fb8..45d0fa3 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
> @@ -10,6 +10,7 @@
> */
>
> #include <drm/drmP.h>
> +#include <drm/drm_atomic_helper.h>
>
> #include <drm/exynos_drm.h>
> #include "exynos_drm_drv.h"
> @@ -149,7 +150,7 @@ void exynos_plane_commit(struct drm_plane *plane)
> struct exynos_plane *exynos_plane = to_exynos_plane(plane);
> struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
>
> - exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
> + exynos_drm_fn_encoder(plane->state->crtc, &overlay->zpos,
> exynos_drm_encoder_plane_commit);
> }
>
> @@ -162,7 +163,7 @@ void exynos_plane_dpms(struct drm_plane *plane, int mode)
> if (exynos_plane->enabled)
> return;
>
> - exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
> + exynos_drm_fn_encoder(plane->state->crtc, &overlay->zpos,
> exynos_drm_encoder_plane_enable);
>
> exynos_plane->enabled = true;
> @@ -170,7 +171,7 @@ void exynos_plane_dpms(struct drm_plane *plane, int mode)
> if (!exynos_plane->enabled)
> return;
>
> - exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
> + exynos_drm_fn_encoder(plane->state->crtc, &overlay->zpos,
> exynos_drm_encoder_plane_disable);
>
> exynos_plane->enabled = false;
> @@ -192,7 +193,7 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
> if (ret < 0)
> return ret;
>
> - plane->crtc = crtc;
> + plane->state->crtc = crtc;
>
> exynos_plane_commit(plane);
> exynos_plane_dpms(plane, DRM_MODE_DPMS_ON);
> @@ -229,6 +230,10 @@ static int exynos_plane_set_property(struct drm_plane *plane,
> if (property == dev_priv->plane_zpos_property) {
> exynos_plane->overlay.zpos = val;
> return 0;
> + } else {
> + return drm_plane_set_property(plane,
> + drm_atomic_get_plane_state(plane, state),
> + property, val, blob_data);
> }
>
> return -EINVAL;
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> index ad6ec4b..d8c2869 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -868,16 +868,17 @@ intel_disable_plane(struct drm_plane *plane)
> {
> struct drm_device *dev = plane->dev;
> struct intel_plane *intel_plane = to_intel_plane(plane);
> + struct drm_plane_state *state = plane->state;
> int ret = 0;
>
> - if (!plane->fb)
> + if (!state->fb)
> return 0;
>
> - if (WARN_ON(!plane->crtc))
> + if (WARN_ON(!state->crtc))
> return -EINVAL;
>
> - intel_enable_primary(plane->crtc);
> - intel_plane->disable_plane(plane, plane->crtc);
> + intel_enable_primary(state->crtc);
> + intel_plane->disable_plane(plane, state->crtc);
>
> if (!intel_plane->obj)
> goto out;
> @@ -966,11 +967,12 @@ out_unlock:
> void intel_plane_restore(struct drm_plane *plane)
> {
> struct intel_plane *intel_plane = to_intel_plane(plane);
> + struct drm_plane_state *state = plane->state;
>
> - if (!plane->crtc || !plane->fb)
> + if (!state->crtc || !state->fb)
> return;
>
> - intel_update_plane(plane, plane->crtc, plane->fb,
> + intel_update_plane(plane, state->crtc, state->fb,
> intel_plane->crtc_x, intel_plane->crtc_y,
> intel_plane->crtc_w, intel_plane->crtc_h,
> intel_plane->src_x, intel_plane->src_y,
> @@ -979,7 +981,9 @@ void intel_plane_restore(struct drm_plane *plane)
>
> void intel_plane_disable(struct drm_plane *plane)
> {
> - if (!plane->crtc || !plane->fb)
> + struct drm_plane_state *state = plane->state;
> +
> + if (!state->crtc || !state->fb)
> return;
>
> intel_disable_plane(plane);
> @@ -989,6 +993,7 @@ static const struct drm_plane_funcs intel_plane_funcs = {
> .update_plane = intel_update_plane,
> .disable_plane = intel_disable_plane,
> .destroy = intel_destroy_plane,
> + .set_property = drm_atomic_helper_plane_set_property,
> };
>
> static uint32_t ilk_plane_formats[] = {
> diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
> index d3fd7ca..1d6a6ee 100644
> --- a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
> +++ b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
> @@ -243,7 +243,7 @@ static void blend_setup(struct drm_crtc *crtc)
> int idx = idxs[pipe_id];
> if (idx > 0) {
> const struct mdp4_format *format =
> - to_mdp4_format(msm_framebuffer_format(plane->fb));
> + to_mdp4_format(msm_framebuffer_format(plane->state->fb));
> alpha[idx-1] = format->alpha_enable;
> }
> mixer_cfg |= mixercfg(mdp4_crtc->mixer, pipe_id, stages[idx]);
> diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp4/mdp4_plane.c
> index 880e96d..8338b1a 100644
> --- a/drivers/gpu/drm/msm/mdp4/mdp4_plane.c
> +++ b/drivers/gpu/drm/msm/mdp4/mdp4_plane.c
> @@ -45,11 +45,14 @@ static int mdp4_plane_update(struct drm_plane *plane,
> uint32_t src_w, uint32_t src_h)
> {
> struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
> + struct drm_plane_state *state = plane->state;
>
> mdp4_plane->enabled = true;
>
> - if (plane->fb)
> - drm_framebuffer_unreference(plane->fb);
> + if (state->fb) {
> + drm_framebuffer_unreference(state->fb);
> + state->fb = NULL;
> + }
>
> drm_framebuffer_reference(fb);
>
> @@ -62,8 +65,8 @@ static int mdp4_plane_disable(struct drm_plane *plane)
> {
> struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
> DBG("%s: disable", mdp4_plane->name);
> - if (plane->crtc)
> - mdp4_crtc_detach(plane->crtc, plane);
> + if (plane->state->crtc)
> + mdp4_crtc_detach(plane->state->crtc, plane);
> return 0;
> }
>
> @@ -87,8 +90,9 @@ void mdp4_plane_install_properties(struct drm_plane *plane,
> int mdp4_plane_set_property(struct drm_plane *plane, void *state,
> struct drm_property *property, uint64_t val, void *blob_data)
> {
> - // XXX
> - return -EINVAL;
> + return drm_plane_set_property(plane,
> + drm_atomic_get_plane_state(plane, state),
> + property, val, blob_data);
> }
>
> static const struct drm_plane_funcs mdp4_plane_funcs = {
> @@ -117,7 +121,7 @@ void mdp4_plane_set_scanout(struct drm_plane *plane,
> msm_gem_get_iova(msm_framebuffer_bo(fb, 0), mdp4_kms->id, &iova);
> mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP0_BASE(pipe), iova);
>
> - plane->fb = fb;
> + plane->state->fb = fb;
> }
>
> #define MDP4_VG_PHASE_STEP_DEFAULT 0x20000000
> diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
> index 5dd22ab..d53a689 100644
> --- a/drivers/gpu/drm/omapdrm/omap_crtc.c
> +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
> @@ -210,7 +210,7 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
> /* and any attached overlay planes: */
> for (i = 0; i < priv->num_planes; i++) {
> struct drm_plane *plane = priv->planes[i];
> - if (plane->crtc == crtc)
> + if (plane->state->crtc == crtc)
> WARN_ON(omap_plane_dpms(plane, mode));
> }
> }
> @@ -651,7 +651,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
>
> omap_crtc->channel = channel;
> omap_crtc->plane = plane;
> - omap_crtc->plane->crtc = crtc;
> + omap_crtc->plane->state->crtc = crtc;
> omap_crtc->name = channel_names[channel];
> omap_crtc->pipe = id;
>
> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
> index 225d0e9..0e15e2c 100644
> --- a/drivers/gpu/drm/omapdrm/omap_drv.c
> +++ b/drivers/gpu/drm/omapdrm/omap_drv.c
> @@ -559,7 +559,7 @@ static void dev_lastclose(struct drm_device *dev)
>
> for (i = 0; i < priv->num_planes; i++) {
> drm_object_property_set_value(&priv->planes[i]->base,
> - &priv->planes[i]->propvals,
> + &priv->planes[i]->state->propvals,
> priv->rotation_prop, 0, NULL);
> }
> }
> diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
> index fe32f1b..d11a879 100644
> --- a/drivers/gpu/drm/omapdrm/omap_plane.c
> +++ b/drivers/gpu/drm/omapdrm/omap_plane.c
> @@ -116,9 +116,10 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
> container_of(apply, struct omap_plane, apply);
> struct omap_drm_window *win = &omap_plane->win;
> struct drm_plane *plane = &omap_plane->base;
> + struct drm_plane_state *state = plane->state;
> struct drm_device *dev = plane->dev;
> struct omap_overlay_info *info = &omap_plane->info;
> - struct drm_crtc *crtc = plane->crtc;
> + struct drm_crtc *crtc = state->crtc;
> enum omap_channel channel;
> bool enabled = omap_plane->enabled && crtc;
> bool ilace, replication;
> @@ -127,7 +128,7 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
> DBG("%s, enabled=%d", omap_plane->name, enabled);
>
> /* if fb has changed, pin new fb: */
> - update_pin(plane, enabled ? plane->fb : NULL);
> + update_pin(plane, enabled ? state->fb : NULL);
>
> if (!enabled) {
> dispc_ovl_enable(omap_plane->id, false);
> @@ -137,7 +138,7 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
> channel = omap_crtc_channel(crtc);
>
> /* update scanout: */
> - omap_framebuffer_update_scanout(plane->fb, win, info);
> + omap_framebuffer_update_scanout(state->fb, win, info);
>
> DBG("%dx%d -> %dx%d (%d)", info->width, info->height,
> info->out_width, info->out_height,
> @@ -179,16 +180,18 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply)
> cb.fxn(cb.arg);
>
> if (omap_plane->enabled) {
> - omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
> + omap_framebuffer_flush(plane->state->fb,
> + info->pos_x, info->pos_y,
> info->out_width, info->out_height);
> }
> }
>
> static int apply(struct drm_plane *plane)
> {
> - if (plane->crtc) {
> + struct drm_plane_state *state = plane->state;
> + if (state->crtc) {
> struct omap_plane *omap_plane = to_omap_plane(plane);
> - return omap_crtc_apply(plane->crtc, &omap_plane->apply);
> + return omap_crtc_apply(state->crtc, &omap_plane->apply);
> }
> return 0;
> }
> @@ -203,6 +206,7 @@ int omap_plane_mode_set(struct drm_plane *plane,
> {
> struct omap_plane *omap_plane = to_omap_plane(plane);
> struct omap_drm_window *win = &omap_plane->win;
> + struct drm_plane_state *state = plane->state;
>
> win->crtc_x = crtc_x;
> win->crtc_y = crtc_y;
> @@ -225,8 +229,8 @@ int omap_plane_mode_set(struct drm_plane *plane,
> omap_plane->apply_done_cb.arg = arg;
> }
>
> - plane->fb = fb;
> - plane->crtc = crtc;
> + state->fb = fb;
> + state->crtc = crtc;
>
> return apply(plane);
> }
> @@ -239,10 +243,12 @@ static int omap_plane_update(struct drm_plane *plane,
> uint32_t src_w, uint32_t src_h)
> {
> struct omap_plane *omap_plane = to_omap_plane(plane);
> + struct drm_plane_state *state = plane->state;
> +
> omap_plane->enabled = true;
>
> - if (plane->fb)
> - drm_framebuffer_unreference(plane->fb);
> + if (state->fb)
> + drm_framebuffer_unreference(state->fb);
>
> drm_framebuffer_reference(fb);
>
> @@ -342,6 +348,10 @@ int omap_plane_set_property(struct drm_plane *plane, void *state,
> DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val);
> omap_plane->info.zorder = val;
> ret = apply(plane);
> + } else {
> + ret = drm_plane_set_property(plane,
> + drm_atomic_get_plane_state(plane, state),
> + property, val, blob_data);
> }
>
> return ret;
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
> index 5691743..909e241 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
> @@ -14,6 +14,7 @@
> #include <drm/drmP.h>
> #include <drm/drm_crtc.h>
> #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_atomic_helper.h>
> #include <drm/drm_fb_cma_helper.h>
> #include <drm/drm_gem_cma_helper.h>
>
> @@ -411,7 +412,9 @@ static int rcar_du_plane_set_property(struct drm_plane *plane,
> else if (property == rgrp->planes.zpos)
> rcar_du_plane_set_zpos(rplane, value);
> else
> - return -EINVAL;
> + return drm_plane_set_property(plane,
> + drm_atomic_get_plane_state(plane, state),
> + property, value, blob_data);
>
> return 0;
> }
> diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> index 035bd67..e62b0f2 100644
> --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> @@ -238,7 +238,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc)
>
> /* Setup planes. */
> list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> - if (plane->crtc == crtc)
> + if (plane->state->crtc == crtc)
> shmob_drm_plane_setup(plane);
> }
>
> diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
> index 060ae03..22da5c1 100644
> --- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c
> +++ b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
> @@ -14,6 +14,7 @@
> #include <drm/drmP.h>
> #include <drm/drm_crtc.h>
> #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_atomic_helper.h>
> #include <drm/drm_fb_cma_helper.h>
> #include <drm/drm_gem_cma_helper.h>
>
> @@ -166,10 +167,10 @@ void shmob_drm_plane_setup(struct drm_plane *plane)
> {
> struct shmob_drm_plane *splane = to_shmob_plane(plane);
>
> - if (plane->fb == NULL)
> + if (plane->state->fb == NULL)
> return;
>
> - __shmob_drm_plane_setup(splane, plane->fb);
> + __shmob_drm_plane_setup(splane, plane->state->fb);
> }
>
> static int
> @@ -228,6 +229,7 @@ static void shmob_drm_plane_destroy(struct drm_plane *plane)
> static const struct drm_plane_funcs shmob_drm_plane_funcs = {
> .update_plane = shmob_drm_plane_update,
> .disable_plane = shmob_drm_plane_disable,
> + .set_property = drm_atomic_helper_plane_set_property,
> .destroy = shmob_drm_plane_destroy,
> };
>
> diff --git a/drivers/gpu/host1x/drm/dc.c b/drivers/gpu/host1x/drm/dc.c
> index b1a05ad..5766010 100644
> --- a/drivers/gpu/host1x/drm/dc.c
> +++ b/drivers/gpu/host1x/drm/dc.c
> @@ -75,11 +75,11 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
>
> static int tegra_plane_disable(struct drm_plane *plane)
> {
> - struct tegra_dc *dc = to_tegra_dc(plane->crtc);
> + struct tegra_dc *dc = to_tegra_dc(plane->state->crtc);
> struct tegra_plane *p = to_tegra_plane(plane);
> unsigned long value;
>
> - if (!plane->crtc)
> + if (!plane->state->crtc)
> return 0;
>
> value = WINDOW_A_SELECT << p->index;
> @@ -104,6 +104,7 @@ static void tegra_plane_destroy(struct drm_plane *plane)
> static const struct drm_plane_funcs tegra_plane_funcs = {
> .update_plane = tegra_plane_update,
> .disable_plane = tegra_plane_disable,
> + .set_property = drm_atomic_helper_plane_set_property,
> .destroy = tegra_plane_destroy,
> };
>
> @@ -267,13 +268,14 @@ static void tegra_crtc_disable(struct drm_crtc *crtc)
> struct drm_plane *plane;
>
> list_for_each_entry(plane, &drm->mode_config.plane_list, head) {
> - if (plane->crtc == crtc) {
> + struct drm_plane_state *state = plane->state;
> + if (state->crtc == crtc) {
> tegra_plane_disable(plane);
> - plane->crtc = NULL;
> + state->crtc = NULL;
>
> - if (plane->fb) {
> - drm_framebuffer_unreference(plane->fb);
> - plane->fb = NULL;
> + if (state->fb) {
> + drm_framebuffer_unreference(state->fb);
> + state->fb = NULL;
> }
> }
> }
> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> index e70cd7b..d0d29e1 100644
> --- a/include/drm/drm_atomic_helper.h
> +++ b/include/drm/drm_atomic_helper.h
> @@ -62,7 +62,9 @@
> * struct drm_atomic_helper_funcs - helper funcs used by the atomic helpers
> */
> struct drm_atomic_helper_funcs {
> - int dummy; /* for now */
> + struct drm_plane_state *(*get_plane_state)(struct drm_plane *plane, void *state);
> + int (*check_plane_state)(struct drm_plane *plane, struct drm_plane_state *pstate);
> + int (*commit_plane_state)(struct drm_plane *plane, struct drm_plane_state *pstate);
> };
>
> const extern struct drm_atomic_helper_funcs drm_atomic_helper_funcs;
> @@ -75,6 +77,37 @@ int drm_atomic_helper_check(struct drm_device *dev, void *state);
> int drm_atomic_helper_commit(struct drm_device *dev, void *state);
> void drm_atomic_helper_end(struct drm_device *dev, void *state);
>
> +int drm_atomic_helper_plane_set_property(struct drm_plane *plane, void *state,
> + struct drm_property *property, uint64_t val, void *blob_data);
> +void drm_atomic_helper_init_plane_state(struct drm_plane *plane,
> + struct drm_plane_state *pstate, void *state);
> +
> +static inline struct drm_plane_state *
> +drm_atomic_get_plane_state(struct drm_plane *plane, void *state)
> +{
> + const struct drm_atomic_helper_funcs *funcs =
> + plane->dev->driver->atomic_helpers;
> + return funcs->get_plane_state(plane, state);
> +}
> +
> +static inline int
> +drm_atomic_check_plane_state(struct drm_plane *plane,
> + struct drm_plane_state *pstate)
> +{
> + const struct drm_atomic_helper_funcs *funcs =
> + plane->dev->driver->atomic_helpers;
> + return funcs->check_plane_state(plane, pstate);
> +}
> +
> +static inline int
> +drm_atomic_commit_plane_state(struct drm_plane *plane,
> + struct drm_plane_state *pstate)
> +{
> + const struct drm_atomic_helper_funcs *funcs =
> + plane->dev->driver->atomic_helpers;
> + return funcs->commit_plane_state(plane, pstate);
> +}
> +
> /**
> * struct drm_atomic_helper_state - the state object used by atomic helpers
> */
> @@ -82,6 +115,8 @@ struct drm_atomic_helper_state {
> struct kref refcount;
> struct drm_device *dev;
> uint32_t flags;
> + struct drm_plane **planes;
> + struct drm_plane_state **pstates;
> };
>
> static inline void
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 8831562..ee46a6a 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -675,6 +675,45 @@ struct drm_plane_funcs {
> };
>
> /**
> + * drm_plane_state - mutable plane state
> + * @new_fb: has the fb been changed
> + * @crtc: currently bound CRTC
> + * @fb: currently bound fb
> + * @crtc_x: left position of visible portion of plane on crtc
> + * @crtc_y: upper position of visible portion of plane on crtc
> + * @crtc_w: width of visible portion of plane on crtc
> + * @crtc_h: height of visible portion of plane on crtc
> + * @src_x: left position of visible portion of plane within
> + * plane (in 16.16)
> + * @src_y: upper position of visible portion of plane within
> + * plane (in 16.16)
> + * @src_w: width of visible portion of plane (in 16.16)
> + * @src_h: height of visible portion of plane (in 16.16)
> + * @propvals: property values
> + * @state: current global/toplevel state object (for atomic) while an
> + * update is in progress, NULL otherwise.
> + */
> +struct drm_plane_state {
> + bool new_fb : 1;
> + struct drm_crtc *crtc;
> + struct drm_framebuffer *fb;
> +
> + /* Signed dest location allows it to be partially off screen */
> + int32_t crtc_x, crtc_y;
> + uint32_t crtc_w, crtc_h;
> +
> + /* Source values are 16.16 fixed point */
> + uint32_t src_x, src_y;
> + uint32_t src_h, src_w;
> +
> + bool enabled;
> +
> + struct drm_object_property_values propvals;
> +
> + void *state;
> +};
> +
> +/**
> * drm_plane - central DRM plane control structure
> * @dev: DRM device this plane belongs to
> * @head: for list management
> @@ -682,8 +721,8 @@ struct drm_plane_funcs {
> * @possible_crtcs: pipes this plane can be bound to
> * @format_types: array of formats supported by this plane
> * @format_count: number of formats supported
> - * @crtc: currently bound CRTC
> - * @fb: currently bound fb
> + * @id: plane number, 0..n
> + * @state: the mutable state
> * @funcs: helper functions
> * @properties: property tracking for this plane
> */
> @@ -697,13 +736,17 @@ struct drm_plane {
> uint32_t *format_types;
> uint32_t format_count;
>
> - struct drm_crtc *crtc;
> - struct drm_framebuffer *fb;
> + int id;
> +
> + /*
> + * State that can be updated from userspace, and atomically
> + * commited or rolled back:
> + */
> + struct drm_plane_state *state;
>
> const struct drm_plane_funcs *funcs;
>
> struct drm_object_properties properties;
> - struct drm_object_property_values propvals;
> };
>
> /**
> @@ -884,8 +927,20 @@ struct drm_mode_config {
> bool poll_running;
> struct delayed_work output_poll_work;
>
> - /* pointers to standard properties */
> + /* just so blob properties can always be in a list: */
> struct list_head property_blob_list;
> +
> + /* pointers to standard properties */
> + struct drm_property *prop_src_x;
> + struct drm_property *prop_src_y;
> + struct drm_property *prop_src_w;
> + struct drm_property *prop_src_h;
> + struct drm_property *prop_crtc_x;
> + struct drm_property *prop_crtc_y;
> + struct drm_property *prop_crtc_w;
> + struct drm_property *prop_crtc_h;
> + struct drm_property *prop_fb_id;
> + struct drm_property *prop_crtc_id;
> struct drm_property *edid_property;
> struct drm_property *dpms_property;
>
> @@ -969,7 +1024,15 @@ extern int drm_plane_init(struct drm_device *dev,
> const uint32_t *formats, uint32_t format_count,
> bool priv);
> extern void drm_plane_cleanup(struct drm_plane *plane);
> -extern void drm_plane_force_disable(struct drm_plane *plane);
> +extern void drm_plane_force_disable(struct drm_plane *plane, void *state);
> +extern int drm_plane_check_state(struct drm_plane *plane,
> + struct drm_plane_state *state);
> +extern void drm_plane_commit_state(struct drm_plane *plane,
> + struct drm_plane_state *state);
> +extern int drm_plane_set_property(struct drm_plane *plane,
> + struct drm_plane_state *state,
> + struct drm_property *property,
> + uint64_t value, void *blob_data);
>
> extern void drm_encoder_cleanup(struct drm_encoder *encoder);
>
> @@ -1023,6 +1086,17 @@ extern int drm_object_property_set_value(struct drm_mode_object *obj,
> extern int drm_object_property_get_value(struct drm_mode_object *obj,
> struct drm_property *property,
> uint64_t *value);
> +
> +int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
> + void *state, struct drm_property *property,
> + uint64_t value, void *blob_data);
> +int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
> + void *state, struct drm_property *property,
> + uint64_t value, void *blob_data);
> +int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
> + void *state, struct drm_property *property,
> + uint64_t value, void *blob_data);
> +
> extern int drm_framebuffer_init(struct drm_device *dev,
> struct drm_framebuffer *fb,
> const struct drm_framebuffer_funcs *funcs);
> --
> 1.8.3.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
--
Matt Roper
Intel Corporation
Embedded Media & Graphics Driver Group
(916) 356-2795
More information about the dri-devel
mailing list