From: Daniel Vetter <daniel@ffwll.ch>
To: Rob Clark <robdclark@gmail.com>
Cc: dri-devel@lists.freedesktop.org
Subject: Re: [PATCH 12/17] drm: convert crtc to properties/state
Date: Mon, 26 May 2014 11:31:10 +0200 [thread overview]
Message-ID: <20140526093110.GC14357@phenom.ffwll.local> (raw)
In-Reply-To: <1400956226-28053-13-git-send-email-robdclark@gmail.com>
On Sat, May 24, 2014 at 02:30:21PM -0400, Rob Clark wrote:
> Break the mutable state of a crtc out into a separate structure
> and use atomic properties mechanism to set crtc attributes. This
> makes it easier to have some helpers for crtc->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.
>
> Signed-off-by: Rob Clark <robdclark@gmail.com>
Same comments about interface design as for the plane patch apply here.
One additional comment below.
> ---
> drivers/gpu/drm/armada/armada_crtc.c | 11 +-
> drivers/gpu/drm/ast/ast_mode.c | 1 +
> drivers/gpu/drm/cirrus/cirrus_mode.c | 1 +
> drivers/gpu/drm/drm_atomic.c | 231 ++++++++++-
> drivers/gpu/drm/drm_crtc.c | 598 ++++++++++++++++++-----------
> drivers/gpu/drm/drm_fb_helper.c | 2 +-
> drivers/gpu/drm/exynos/exynos_drm_crtc.c | 7 +-
> drivers/gpu/drm/gma500/cdv_intel_display.c | 1 +
> drivers/gpu/drm/gma500/psb_intel_display.c | 1 +
> drivers/gpu/drm/i915/intel_display.c | 1 +
> drivers/gpu/drm/mgag200/mgag200_mode.c | 1 +
> drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c | 6 +-
> drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 6 +-
> drivers/gpu/drm/nouveau/dispnv04/crtc.c | 1 +
> drivers/gpu/drm/nouveau/nv50_display.c | 1 +
> drivers/gpu/drm/omapdrm/omap_crtc.c | 12 +-
> drivers/gpu/drm/omapdrm/omap_drv.c | 2 +-
> drivers/gpu/drm/qxl/qxl_display.c | 2 +
> drivers/gpu/drm/radeon/radeon_display.c | 2 +
> drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 2 +
> drivers/gpu/drm/shmobile/shmob_drm_crtc.c | 2 +
> drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 1 +
> drivers/gpu/drm/udl/udl_modeset.c | 2 +
> drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 1 +
> drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 1 +
> include/drm/drm_atomic.h | 29 ++
> include/drm/drm_crtc.h | 103 ++++-
> 27 files changed, 785 insertions(+), 243 deletions(-)
>
> diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
> index 7d3c649..6237af4 100644
> --- a/drivers/gpu/drm/armada/armada_crtc.c
> +++ b/drivers/gpu/drm/armada/armada_crtc.c
> @@ -9,6 +9,7 @@
> #include <linux/clk.h>
> #include <drm/drmP.h>
> #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_atomic.h>
> #include "armada_crtc.h"
> #include "armada_drm.h"
> #include "armada_fb.h"
> @@ -966,7 +967,12 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc,
> {
> struct armada_private *priv = crtc->dev->dev_private;
> struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
> + struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
> bool update_csc = false;
> + int ret = 0;
> +
> + if (IS_ERR(cstate))
> + return PTR_ERR(cstate);
>
> if (property == priv->csc_yuv_prop) {
> dcrtc->csc_yuv_mode = val;
> @@ -974,6 +980,9 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc,
> } else if (property == priv->csc_rgb_prop) {
> dcrtc->csc_rgb_mode = val;
> update_csc = true;
> + } else {
> + ret = drm_crtc_set_property(crtc, cstate, property,
> + val, blob_data);
> }
>
> if (update_csc) {
> @@ -984,7 +993,7 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc,
> writel_relaxed(val, dcrtc->base + LCD_SPU_IOPAD_CONTROL);
> }
>
> - return 0;
> + return ret;
> }
>
> static struct drm_crtc_funcs armada_crtc_funcs = {
> diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
> index 114aee9..c08e0e1 100644
> --- a/drivers/gpu/drm/ast/ast_mode.c
> +++ b/drivers/gpu/drm/ast/ast_mode.c
> @@ -632,6 +632,7 @@ static const struct drm_crtc_funcs ast_crtc_funcs = {
> .cursor_move = ast_cursor_move,
> .reset = ast_crtc_reset,
> .set_config = drm_crtc_helper_set_config,
> + .set_property = drm_atomic_crtc_set_property,
> .gamma_set = ast_crtc_gamma_set,
> .destroy = ast_crtc_destroy,
> };
> diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
> index 49332c5..3c4428c 100644
> --- a/drivers/gpu/drm/cirrus/cirrus_mode.c
> +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
> @@ -366,6 +366,7 @@ static void cirrus_crtc_destroy(struct drm_crtc *crtc)
> static const struct drm_crtc_funcs cirrus_crtc_funcs = {
> .gamma_set = cirrus_crtc_gamma_set,
> .set_config = drm_crtc_helper_set_config,
> + .set_property = drm_atomic_crtc_set_property,
> .destroy = cirrus_crtc_destroy,
> };
>
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 403ffc5..863a0fe 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -48,11 +48,13 @@ struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev,
> {
> struct drm_atomic_state *state;
> int nplanes = dev->mode_config.num_total_plane;
> + int ncrtcs = dev->mode_config.num_crtc;
> int sz;
> void *ptr;
>
> sz = sizeof(*state);
> sz += (sizeof(state->planes) + sizeof(state->pstates)) * nplanes;
> + sz += (sizeof(state->crtcs) + sizeof(state->cstates)) * ncrtcs;
>
> ptr = kzalloc(sz, GFP_KERNEL);
>
> @@ -74,6 +76,12 @@ struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev,
> state->pstates = ptr;
> ptr = &state->pstates[nplanes];
>
> + state->crtcs = ptr;
> + ptr = &state->crtcs[ncrtcs];
> +
> + state->cstates = ptr;
> + ptr = &state->cstates[ncrtcs];
> +
> return state;
> }
> EXPORT_SYMBOL(drm_atomic_begin);
> @@ -92,7 +100,18 @@ int drm_atomic_set_event(struct drm_device *dev,
> struct drm_atomic_state *state, struct drm_mode_object *obj,
> struct drm_pending_vblank_event *event)
> {
> - return -EINVAL; /* for now */
> + switch (obj->type) {
> + case DRM_MODE_OBJECT_CRTC: {
> + struct drm_crtc_state *cstate =
> + drm_atomic_get_crtc_state(obj_to_crtc(obj), state);
> + if (IS_ERR(cstate))
> + return PTR_ERR(cstate);
> + cstate->event = event;
> + return 0;
> + }
> + default:
> + return -EINVAL;
> + }
Hm, I think if we only want completion events on crtcs (which I agree on)
then we should make the set_event interface more specific by passing
struct drm_crtc * and only call it for crtcs.
> }
> EXPORT_SYMBOL(drm_atomic_set_event);
>
> @@ -111,6 +130,7 @@ int drm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
> {
> struct drm_atomic_state *a = state;
> int nplanes = dev->mode_config.num_total_plane;
> + int ncrtcs = dev->mode_config.num_crtc;
> int i, ret = 0;
>
> for (i = 0; i < nplanes; i++) {
> @@ -120,6 +140,13 @@ int drm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
> break;
> }
> }
> + for (i = 0; i < ncrtcs; i++) {
> + if (a->crtcs[i]) {
> + ret = drm_atomic_check_crtc_state(a->crtcs[i], a->cstates[i]);
> + if (ret)
> + break;
> + }
> + }
>
> a->acquire_ctx.frozen = true;
>
> @@ -203,6 +230,7 @@ static void commit_locks(struct drm_atomic_state *a,
> {
> struct drm_device *dev = a->dev;
> int nplanes = dev->mode_config.num_total_plane;
> + int ncrtcs = dev->mode_config.num_crtc;
> int i;
>
> for (i = 0; i < nplanes; i++) {
> @@ -213,6 +241,14 @@ static void commit_locks(struct drm_atomic_state *a,
> }
> }
>
> + for (i = 0; i < ncrtcs; i++) {
> + struct drm_crtc *crtc = a->crtcs[i];
> + if (crtc) {
> + crtc->state->state = NULL;
> + drm_crtc_destroy_state(crtc, a->cstates[i]);
> + }
> + }
> +
> /* and properly release them (clear in_atomic, remove from list): */
> drm_modeset_drop_locks(&a->acquire_ctx);
> ww_acquire_fini(ww_ctx);
> @@ -223,8 +259,18 @@ static int atomic_commit(struct drm_atomic_state *a,
> struct ww_acquire_ctx *ww_ctx)
> {
> int nplanes = a->dev->mode_config.num_total_plane;
> + int ncrtcs = a->dev->mode_config.num_crtc;
> int i, ret = 0;
>
> + for (i = 0; i < ncrtcs; i++) {
> + struct drm_crtc *crtc = a->crtcs[i];
> + if (crtc) {
> + ret = drm_atomic_commit_crtc_state(crtc, a->cstates[i]);
> + if (ret)
> + break;
> + }
> + }
> +
> for (i = 0; i < nplanes; i++) {
> struct drm_plane *plane = a->planes[i];
> if (plane) {
> @@ -403,6 +449,7 @@ static int
> commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate)
> {
> struct drm_atomic_state *a = pstate->state;
> + struct drm_crtc_state *cstate = NULL;
> struct drm_framebuffer *old_fb = plane->fb;
> struct drm_framebuffer *fb = pstate->fb;
> bool enabled = pstate->crtc && fb;
> @@ -425,8 +472,11 @@ commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate)
> }
> } else {
> struct drm_crtc *crtc = pstate->crtc;
> + cstate = drm_atomic_get_crtc_state(crtc, pstate->state);
> if (pstate->update_plane ||
> (pstate->new_fb && !can_flip(plane, pstate))) {
> +/* TODO pass event to update_plane().. */
> +WARN_ON(cstate->event);
> ret = plane->funcs->update_plane(plane, crtc, pstate->fb,
> pstate->crtc_x, pstate->crtc_y,
> pstate->crtc_w, pstate->crtc_h,
> @@ -443,7 +493,7 @@ commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate)
> }
>
> } else if (pstate->new_fb) {
> - ret = crtc->funcs->page_flip(crtc, fb, NULL, a->flags);
> + ret = crtc->funcs->page_flip(crtc, fb, cstate->event, a->flags);
> if (ret == 0) {
> /*
> * Warn if the driver hasn't properly updated the plane->fb
> @@ -473,9 +523,10 @@ commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate)
> * original code.
> */
> swap_plane_state(plane, pstate->state);
> + if (cstate)
> + cstate->event = NULL;
> }
>
> -
> if (fb)
> drm_framebuffer_unreference(fb);
> if (old_fb)
> @@ -484,8 +535,182 @@ commit_plane_state(struct drm_plane *plane, struct drm_plane_state *pstate)
> return ret;
> }
>
> +int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
> + struct drm_atomic_state *state, struct drm_property *property,
> + uint64_t val, void *blob_data)
> +{
> + struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
> + if (IS_ERR(cstate))
> + return PTR_ERR(cstate);
> + return drm_crtc_set_property(crtc, cstate, property, val, blob_data);
> +}
> +EXPORT_SYMBOL(drm_atomic_crtc_set_property);
> +
> +static void init_crtc_state(struct drm_crtc *crtc,
> + struct drm_crtc_state *cstate, struct drm_atomic_state *state)
> +{
> + /* snapshot current state: */
> + *cstate = *crtc->state;
> + cstate->state = state;
> +
> + if (cstate->connector_ids) {
> + int sz = cstate->num_connector_ids * sizeof(cstate->connector_ids[0]);
> + cstate->connector_ids = kmemdup(cstate->connector_ids, sz, GFP_KERNEL);
> + }
> +
> + /* this should never happen.. but make sure! */
> + WARN_ON(cstate->event);
> + cstate->event = NULL;
> +}
> +
> +struct drm_crtc_state *
> +drm_atomic_get_crtc_state(struct drm_crtc *crtc, struct drm_atomic_state *a)
> +{
> + struct drm_crtc_state *cstate;
> + int ret;
> +
> + cstate = a->cstates[crtc->id];
> +
> + if (!cstate) {
> + ret = drm_modeset_lock(&crtc->mutex, &a->acquire_ctx);
> + if (ret)
> + return ERR_PTR(ret);
> +
> + cstate = drm_crtc_create_state(crtc);
> + if (!cstate)
> + return ERR_PTR(-ENOMEM);
> + init_crtc_state(crtc, cstate, a);
> + a->crtcs[crtc->id] = crtc;
> + a->cstates[crtc->id] = cstate;
> +
> + /* we'll need it later, so make sure we have state
> + * for primary plane too:
> + */
> + drm_atomic_get_plane_state(crtc->primary, a);
I haven't figured out why. With primary planes I don't really see a need
for this. If we need it to implement the legacy setcrtc interface, then
that should be done there, not here.
> + }
> + return cstate;
> +}
> +EXPORT_SYMBOL(drm_atomic_get_crtc_state);
> +
> +static void
> +swap_crtc_state(struct drm_crtc *crtc, struct drm_atomic_state *a)
> +{
> + struct drm_crtc_state *cstate = a->cstates[crtc->id];
> + struct drm_device *dev = crtc->dev;
> + struct drm_pending_vblank_event *event = cstate->event;
> +
> + if (event) {
> + /* hrm, need to sort out a better way to send events for
> + * other-than-pageflip.. but modeset is not async, so:
> + */
> + unsigned long flags;
> + spin_lock_irqsave(&dev->event_lock, flags);
> + drm_send_vblank_event(dev, crtc->id, event);
> + cstate->event = NULL;
> + spin_unlock_irqrestore(&dev->event_lock, flags);
> + }
> +
> + /* clear transient state (only valid during atomic update): */
> + cstate->set_config = false;
> + cstate->connectors_change = false;
> +
> + swap(crtc->state, a->cstates[crtc->id]);
> + crtc->base.propvals = &crtc->state->propvals;
> +}
> +
> +static struct drm_connector **get_connector_set(struct drm_device *dev,
> + uint32_t *connector_ids, uint32_t num_connector_ids)
> +{
> + struct drm_connector **connector_set = NULL;
> + int i;
> +
> + connector_set = kmalloc(num_connector_ids *
> + sizeof(struct drm_connector *),
> + GFP_KERNEL);
> + if (!connector_set)
> + return NULL;
> +
> + for (i = 0; i < num_connector_ids; i++)
> + connector_set[i] = drm_connector_find(dev, connector_ids[i]);
> +
> + return connector_set;
> +}
> +
> +static int set_config(struct drm_crtc *crtc, struct drm_crtc_state *cstate)
> +{
> + struct drm_device *dev = crtc->dev;
> + struct drm_plane_state *pstate =
> + drm_atomic_get_plane_state(crtc->primary, cstate->state);
> + struct drm_framebuffer *fb = pstate->fb;
> + struct drm_connector **connector_set = get_connector_set(crtc->dev,
> + cstate->connector_ids, cstate->num_connector_ids);
> + struct drm_display_mode *mode = drm_crtc_get_mode(crtc, cstate);
> + struct drm_mode_set set = {
> + .crtc = crtc,
> + .x = pstate->src_x >> 16,
> + .y = pstate->src_y >> 16,
> + .mode = mode,
> + .num_connectors = cstate->num_connector_ids,
> + .connectors = connector_set,
> + .fb = fb,
> + };
> + int ret;
> +
> + if (IS_ERR(mode)) {
> + ret = PTR_ERR(mode);
> + return ret;
> + }
> +
> + if (fb)
> + drm_framebuffer_reference(fb);
> +
> + ret = drm_mode_set_config_internal(&set);
> + if (!ret) {
> + swap_crtc_state(crtc, cstate->state);
> + pstate->new_fb = pstate->update_plane = false;
> + }
> +
> + if (fb)
> + drm_framebuffer_unreference(fb);
> +
> + kfree(connector_set);
> + if (mode)
> + drm_mode_destroy(dev, mode);
> + return ret;
> +}
> +
> +static int
> +commit_crtc_state(struct drm_crtc *crtc,
> + struct drm_crtc_state *cstate)
> +{
> + struct drm_plane_state *pstate =
> + drm_atomic_get_plane_state(crtc->primary, cstate->state);
> + int ret = -EINVAL;
> +
> + if (cstate->set_config)
> + return set_config(crtc, cstate);
> +
> + if (!pstate->fb) {
> + /* disable */
> + struct drm_mode_set set = {
> + .crtc = crtc,
> + .fb = NULL,
> + };
> +
> + ret = drm_mode_set_config_internal(&set);
> + if (!ret) {
> + swap_crtc_state(crtc, cstate->state);
> + }
> + }
> +
> + return ret;
> +}
> +
> const struct drm_atomic_funcs drm_atomic_funcs = {
> .check_plane_state = drm_plane_check_state,
> .commit_plane_state = commit_plane_state,
> +
> + .check_crtc_state = drm_crtc_check_state,
> + .commit_crtc_state = commit_crtc_state,
> };
> EXPORT_SYMBOL(drm_atomic_funcs);
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index b556a31..e14d517 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -689,10 +689,7 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
> void drm_framebuffer_remove(struct drm_framebuffer *fb)
> {
> struct drm_device *dev = fb->dev;
> - struct drm_crtc *crtc;
> struct drm_plane *plane;
> - struct drm_mode_set set;
> - int ret;
>
> WARN_ON(!list_empty(&fb->filp_head));
>
> @@ -712,7 +709,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
> * in this manner.
> */
> if (atomic_read(&fb->refcount.refcount) > 1) {
> - void *state;
> + struct drm_atomic_state *state;
>
> state = dev->driver->atomic_begin(dev, 0);
> if (IS_ERR(state)) {
> @@ -720,24 +717,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
> return;
> }
>
> - /* TODO once CRTC is converted to state/properties, we can push the
> - * locking down into drm_atomic_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->primary->fb == fb) {
> - /* should turn off the crtc */
> - memset(&set, 0, sizeof(struct drm_mode_set));
> - set.crtc = crtc;
> - set.fb = NULL;
> - ret = drm_mode_set_config_internal(&set);
> - if (ret)
> - DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
> - }
> - }
> -
> + /* remove from any plane */
> list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> if (plane->fb == fb)
> drm_plane_force_disable(plane, state);
> @@ -750,8 +730,6 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
> dev->driver->atomic_commit(dev, state);
>
> dev->driver->atomic_end(dev, state);
> -
> - drm_modeset_unlock_all(dev);
> }
>
> drm_framebuffer_unreference(fb);
> @@ -782,9 +760,13 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
> struct drm_mode_config *config = &dev->mode_config;
> int ret;
>
> + /* this is now required: */
> + WARN_ON(!funcs->set_property);
> +
> crtc->dev = dev;
> crtc->funcs = funcs;
> - crtc->invert_dimensions = false;
> + crtc->state = drm_crtc_create_state(crtc);
> + crtc->state->invert_dimensions = false;
>
> drm_modeset_lock_all(dev);
> drm_modeset_lock_init(&crtc->mutex);
> @@ -796,14 +778,17 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
> goto out;
>
> crtc->base.properties = &crtc->properties;
> - crtc->base.propvals = &crtc->propvals;
> + crtc->base.propvals = &crtc->state->propvals;
>
> list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
> dev->mode_config.num_crtc++;
>
> crtc->primary = primary;
> if (primary)
> - primary->possible_crtcs = 1 << drm_crtc_index(crtc);
> + primary->possible_crtcs = 1 << crtc->id;
> +
> + drm_object_attach_property(&crtc->base, config->prop_mode, 0);
> + drm_object_attach_property(&crtc->base, config->prop_connector_ids, 0);
>
> out:
> drm_modeset_unlock_all(dev);
> @@ -832,31 +817,245 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
> drm_mode_object_put(dev, &crtc->base);
> list_del(&crtc->head);
> dev->mode_config.num_crtc--;
> +
> + drm_crtc_destroy_state(crtc, crtc->state);
> }
> EXPORT_SYMBOL(drm_crtc_cleanup);
>
> -/**
> - * drm_crtc_index - find the index of a registered CRTC
> - * @crtc: CRTC to find index for
> - *
> - * Given a registered CRTC, return the index of that CRTC within a DRM
> - * device's list of CRTCs.
> - */
> -unsigned int drm_crtc_index(struct drm_crtc *crtc)
> +/* get display-mode from user-mode */
> +struct drm_display_mode *drm_crtc_get_mode(struct drm_crtc *crtc,
> + struct drm_crtc_state *cstate)
> {
> - unsigned int index = 0;
> - struct drm_crtc *tmp;
> + struct drm_display_mode *mode = NULL;
> + if (cstate->mode_valid) {
> + struct drm_device *dev = crtc->dev;
> + int ret;
>
> - list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
> - if (tmp == crtc)
> - return index;
> + mode = drm_mode_create(dev);
> + if (!mode)
> + return ERR_PTR(-ENOMEM);
> +
> + ret = drm_crtc_convert_umode(mode, &cstate->mode);
> + if (ret) {
> + DRM_DEBUG_KMS("Invalid mode\n");
> + drm_mode_destroy(dev, mode);
> + return ERR_PTR(ret);
> + }
>
> - index++;
> + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
> }
> + return mode;
> +}
>
> - BUG();
> +static int connector_idx(struct drm_crtc_state *state,
> + uint32_t connector_id)
> +{
> + int i;
> + for (i = 0; i < state->num_connector_ids; i++)
> + if (state->connector_ids[i] == connector_id)
> + return i;
> + return -1;
> +}
> +
> +static int remove_connector(struct drm_crtc *ocrtc,
> + struct drm_crtc_state *ostate, struct drm_atomic_state *state,
> + int idx)
> +{
> + struct drm_mode_config *config = &ocrtc->dev->mode_config;
> + uint32_t *new_connector_ids;
> + int a, b;
> +
> + /* before deletion point: */
> + a = idx * sizeof(ostate->connector_ids[0]);
> +
> + /* after deletion point: */
> + b = (ostate->num_connector_ids - 1 - idx) *
> + sizeof(ostate->connector_ids[0]);
> +
> + new_connector_ids = kmalloc(a+b, GFP_KERNEL);
> + if (!new_connector_ids)
> + return -ENOMEM;
> +
> + memcpy(new_connector_ids, ostate->connector_ids, a);
> + memcpy(&new_connector_ids[idx],
> + &ostate->connector_ids[idx + 1], b);
> +
> + return drm_mode_crtc_set_obj_prop(ocrtc, state,
> + config->prop_connector_ids, a + b,
> + new_connector_ids);
> }
> -EXPORT_SYMBOL(drm_crtc_index);
> +
> +static int check_connectors(struct drm_crtc *crtc,
> + struct drm_atomic_state *state, bool fix,
> + uint32_t *connector_ids, uint32_t num_connector_ids)
> +{
> + struct drm_mode_config *config = &crtc->dev->mode_config;
> + struct drm_crtc *ocrtc; /* other connector */
> +
> + list_for_each_entry(ocrtc, &config->crtc_list, head) {
> + struct drm_crtc_state *ostate; /* other state */
> + unsigned i;
> +
> + if (ocrtc == crtc)
> + continue;
> +
> + ostate = drm_atomic_get_crtc_state(crtc, state);
> + if (IS_ERR(ostate))
> + return PTR_ERR(ostate);
> +
> + for (i = 0; i < num_connector_ids; i++) {
> + struct drm_connector *connector;
> + uint32_t cid = connector_ids[i];
> + int idx;
> +
> +retry:
> + idx = connector_idx(ostate, cid);
> + if (idx < 0)
> + continue;
> +
> + if (fix) {
> + int ret = remove_connector(ocrtc,
> + ostate, state, idx);
> + if (ret)
> + return ret;
> + goto retry;
> + }
> +
> + connector = drm_connector_find(crtc->dev, cid);
> + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] already in use\n",
> + connector->base.id,
> + drm_get_connector_name(connector));
> + return -EINVAL;
> + }
> + }
> +
> + return 0;
> +}
> +
> +int drm_crtc_check_state(struct drm_crtc *crtc,
> + struct drm_crtc_state *state)
> +{
> + struct drm_plane *primary = crtc->primary;
> + struct drm_plane_state *pstate =
> + drm_atomic_get_plane_state(primary, state->state);
> + struct drm_framebuffer *fb = pstate->fb;
> + int hdisplay, vdisplay;
> + struct drm_display_mode *mode = drm_crtc_get_mode(crtc, state);
> + unsigned x, y;
> +
> + if (IS_ERR(mode))
> + return PTR_ERR(mode);
> +
> + /* disabling the crtc is allowed: */
> + if (!(fb && state->mode_valid))
> + return 0;
> +
> + hdisplay = state->mode.hdisplay;
> + vdisplay = state->mode.vdisplay;
> +
> + if (mode && drm_mode_is_stereo(mode)) {
> + struct drm_display_mode adjusted = *mode;
> +
> + drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
> + hdisplay = adjusted.crtc_hdisplay;
> + vdisplay = adjusted.crtc_vdisplay;
> + }
> +
> + if (state->invert_dimensions)
> + swap(hdisplay, vdisplay);
> +
> + x = pstate->src_x >> 16;
> + y = pstate->src_y >> 16;
> +
> + if (hdisplay > fb->width ||
> + vdisplay > fb->height ||
> + x > fb->width - hdisplay ||
> + y > fb->height - vdisplay) {
> + DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
> + fb->width, fb->height, hdisplay, vdisplay,
> + x, y, state->invert_dimensions ? " (inverted)" : "");
> + return -ENOSPC;
> + }
> +
> + if (crtc->enabled && !state->set_config) {
> + if (primary->state->fb->pixel_format != fb->pixel_format) {
> + DRM_DEBUG_KMS("Page flip is not allowed to "
> + "change frame buffer format.\n");
> + return -EINVAL;
> + }
> + }
> +
> + if (state->num_connector_ids == 0) {
> + DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
> + return -EINVAL;
> + }
> +
> + if (state->connectors_change) {
> + int ret = check_connectors(crtc, state->state, false,
> + state->connector_ids, state->num_connector_ids);
> + if (ret)
> + return ret;
> + }
> +
> + if (mode)
> + drm_mode_destroy(crtc->dev, mode);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_crtc_check_state);
> +
> +void drm_crtc_commit_state(struct drm_crtc *crtc,
> + struct drm_crtc_state *state)
> +{
> + crtc->state = state;
> + crtc->base.propvals = &state->propvals;
> +}
> +EXPORT_SYMBOL(drm_crtc_commit_state);
> +
> +int drm_crtc_set_property(struct drm_crtc *crtc,
> + struct drm_crtc_state *state,
> + struct drm_property *property,
> + uint64_t value, void *blob_data)
> +{
> + struct drm_device *dev = crtc->dev;
> + struct drm_mode_config *config = &dev->mode_config;
> +
> + /* grab primary plane state now, to ensure locks are held, etc. */
> + drm_atomic_get_plane_state(crtc->primary, state->state);
> +
> + drm_object_property_set_value(&crtc->base,
> + &state->propvals, property, value, blob_data);
> +
> + if (property == config->prop_mode) {
> + if (!blob_data) {
> + memset(&state->mode, 0, sizeof(state->mode));
> + state->mode_valid = false;
> + } else {
> + /* check size: */
> + if (value < sizeof(struct drm_mode_modeinfo))
> + return -EINVAL;
> + state->mode = *(struct drm_mode_modeinfo *)blob_data;
> + state->mode_valid = true;
> + }
> + state->set_config = true;
> + } else if (property == config->prop_connector_ids) {
> + /* if connector-id's changing, we need to have all the locks: */
> + struct drm_atomic_state *a = state->state;
> + int ret = drm_modeset_lock_all_crtcs(crtc->dev, &a->acquire_ctx);
> + if (ret)
> + return ret;
> + state->connectors_change = true;
> + state->num_connector_ids = value / sizeof(state->connector_ids[0]);
> + kfree(state->connector_ids);
> + state->connector_ids = blob_data;
> + state->set_config = true;
> + } else {
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_crtc_set_property);
>
> /*
> * drm_mode_remove - remove and free a mode
> @@ -1239,6 +1438,10 @@ int drm_plane_check_state(struct drm_plane *plane,
> if (!fb)
> return 0;
>
> + /* we'll need this later during commit: */
> + if (state->crtc)
> + drm_atomic_get_crtc_state(state->crtc, state->state);
> +
> fb_width = fb->width << 16;
> fb_height = fb->height << 16;
>
> @@ -1465,6 +1668,16 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
> return -ENOMEM;
> dev->mode_config.prop_crtc_id = prop;
>
> + prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "CONNECTOR_IDS", 0);
> + if (!prop)
> + return -ENOMEM;
> + dev->mode_config.prop_connector_ids = prop;
> +
> + prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "MODE", 0);
> + if (!prop)
> + return -ENOMEM;
> + dev->mode_config.prop_mode = prop;
> +
> return 0;
> }
>
> @@ -1754,7 +1967,7 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
> * Returns:
> * Zero on success, errno on failure.
> */
> -static int drm_crtc_convert_umode(struct drm_display_mode *out,
> +int drm_crtc_convert_umode(struct drm_display_mode *out,
> const struct drm_mode_modeinfo *in)
> {
> if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
> @@ -2001,8 +2214,8 @@ int drm_mode_getcrtc(struct drm_device *dev,
> goto out;
> }
>
> - crtc_resp->x = crtc->x;
> - crtc_resp->y = crtc->y;
> + crtc_resp->x = crtc->primary->state->src_x >> 16;
> + crtc_resp->y = crtc->primary->state->src_y >> 16;
> crtc_resp->gamma_size = crtc->gamma_size;
> if (crtc->primary->fb)
> crtc_resp->fb_id = crtc->primary->fb->base.id;
> @@ -2495,7 +2708,7 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc,
> vdisplay = adjusted.crtc_vdisplay;
> }
>
> - if (crtc->invert_dimensions)
> + if (crtc->state->invert_dimensions)
> swap(hdisplay, vdisplay);
>
> if (hdisplay > fb->width ||
> @@ -2504,7 +2717,7 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc,
> y > fb->height - vdisplay) {
> DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
> fb->width, fb->height, hdisplay, vdisplay, x, y,
> - crtc->invert_dimensions ? " (inverted)" : "");
> + crtc->state->invert_dimensions ? " (inverted)" : "");
> return -ENOSPC;
> }
>
> @@ -2531,22 +2744,15 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
> struct drm_mode_config *config = &dev->mode_config;
> struct drm_mode_crtc *crtc_req = data;
> struct drm_crtc *crtc;
> - struct drm_connector **connector_set = NULL, *connector;
> - struct drm_framebuffer *fb = NULL;
> - struct drm_display_mode *mode = NULL;
> - struct drm_mode_set set;
> - uint32_t __user *set_connectors_ptr;
> + uint32_t fb_id = -1;
> + uint32_t *connector_ids = NULL;
> + struct drm_atomic_state *state = NULL;
> int ret;
> int i;
>
> if (!drm_core_check_feature(dev, DRIVER_MODESET))
> return -EINVAL;
>
> - /* For some reason crtc x/y offsets are signed internally. */
> - if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX)
> - return -ERANGE;
> -
> - drm_modeset_lock_all(dev);
> crtc = drm_crtc_find(dev, crtc_req->crtc_id);
> if (!crtc) {
> DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
> @@ -2564,55 +2770,15 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
> ret = -EINVAL;
> goto out;
> }
> - fb = crtc->primary->fb;
> - /* Make refcounting symmetric with the lookup path. */
> - drm_framebuffer_reference(fb);
> + fb_id = crtc->primary->fb->base.id;
> } else {
> - fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
> - if (!fb) {
> - DRM_DEBUG_KMS("Unknown FB ID%d\n",
> - crtc_req->fb_id);
> - ret = -ENOENT;
> - goto out;
> - }
> - }
> -
> - mode = drm_mode_create(dev);
> - if (!mode) {
> - ret = -ENOMEM;
> - goto out;
> + fb_id = crtc_req->fb_id;
> }
> -
> - ret = drm_crtc_convert_umode(mode, &crtc_req->mode);
> - if (ret) {
> - DRM_DEBUG_KMS("Invalid mode\n");
> - goto out;
> - }
> -
> - drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
> -
> - ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
> - mode, fb);
> - if (ret)
> - goto out;
> -
> - }
> -
> - if (crtc_req->count_connectors == 0 && mode) {
> - DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
> - ret = -EINVAL;
> - goto out;
> - }
> -
> - if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
> - DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
> - crtc_req->count_connectors);
> - ret = -EINVAL;
> - goto out;
> }
>
> if (crtc_req->count_connectors > 0) {
> - u32 out_id;
> + uint32_t __user *set_connectors_ptr =
> + (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
>
> /* Avoid unbounded kernel memory allocation */
> if (crtc_req->count_connectors > config->num_connector) {
> @@ -2620,52 +2786,65 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
> goto out;
> }
>
> - connector_set = kmalloc(crtc_req->count_connectors *
> - sizeof(struct drm_connector *),
> + connector_ids = kmalloc(crtc_req->count_connectors *
> + sizeof(connector_ids[0]),
> GFP_KERNEL);
> - if (!connector_set) {
> + if (!connector_ids) {
> ret = -ENOMEM;
> goto out;
> }
>
> for (i = 0; i < crtc_req->count_connectors; i++) {
> - set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
> + u32 out_id;
> +
> if (get_user(out_id, &set_connectors_ptr[i])) {
> ret = -EFAULT;
> goto out;
> }
> -
> - connector = drm_connector_find(dev, out_id);
> - if (!connector) {
> - DRM_DEBUG_KMS("Connector id %d unknown\n",
> - out_id);
> - ret = -ENOENT;
> - goto out;
> - }
> - DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
> - connector->base.id,
> - drm_get_connector_name(connector));
> -
> - connector_set[i] = connector;
> + connector_ids[i] = out_id;
> }
> }
>
> - set.crtc = crtc;
> - set.x = crtc_req->x;
> - set.y = crtc_req->y;
> - set.mode = mode;
> - set.connectors = connector_set;
> - set.num_connectors = crtc_req->count_connectors;
> - set.fb = fb;
> - ret = drm_mode_set_config_internal(&set);
> +retry:
> + state = dev->driver->atomic_begin(dev, 0);
> + if (IS_ERR(state))
> + return PTR_ERR(state);
>
> -out:
> - if (fb)
> - drm_framebuffer_unreference(fb);
> + /* If connectors change, we need to check if we need to steal one
> + * from another CRTC.. setcrtc makes this implicit, but atomic
> + * treats it as an error so we need to handle here:
> + */
> + ret = check_connectors(crtc, state, true,
> + connector_ids, crtc_req->count_connectors);
> + if (ret)
> + goto out;
>
> - kfree(connector_set);
> - drm_mode_destroy(dev, mode);
> - drm_modeset_unlock_all(dev);
> + ret =
> + drm_mode_crtc_set_obj_prop(crtc, state,
> + config->prop_mode, sizeof(crtc_req->mode), &crtc_req->mode) ||
> + drm_mode_crtc_set_obj_prop(crtc, state,
> + config->prop_connector_ids,
> + crtc_req->count_connectors * sizeof(connector_ids[0]),
> + connector_ids) ||
> + drm_mode_plane_set_obj_prop(crtc->primary, state,
> + config->prop_crtc_id, crtc->base.id, NULL) ||
> + drm_mode_plane_set_obj_prop(crtc->primary, state,
> + config->prop_fb_id, fb_id, NULL) ||
> + drm_mode_plane_set_obj_prop(crtc->primary, state,
> + config->prop_src_x, crtc_req->x << 16, NULL) ||
> + drm_mode_plane_set_obj_prop(crtc->primary, state,
> + config->prop_src_y, crtc_req->y << 16, NULL) ||
> + dev->driver->atomic_check(dev, state);
> + if (ret)
> + goto out;
> +
> + ret = dev->driver->atomic_commit(dev, state);
> +
> +out:
> + if (state)
> + dev->driver->atomic_end(dev, state);
> + if (ret == -EDEADLK)
> + goto retry;
> return ret;
> }
>
> @@ -4028,9 +4207,6 @@ int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
> if (crtc->funcs->set_property)
> ret = crtc->funcs->set_property(crtc, state, property,
> value, blob_data);
> - if (!ret)
> - drm_object_property_set_value(&crtc->base, &crtc->propvals,
> - property, value, NULL);
>
> return ret;
> }
> @@ -4424,6 +4600,51 @@ out:
> return ret;
> }
>
> +static struct drm_pending_vblank_event *create_vblank_event(
> + struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data)
> +{
> + struct drm_pending_vblank_event *e = NULL;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&dev->event_lock, flags);
> + if (file_priv->event_space < sizeof e->event) {
> + spin_unlock_irqrestore(&dev->event_lock, flags);
> + goto out;
> + }
> + file_priv->event_space -= sizeof e->event;
> + spin_unlock_irqrestore(&dev->event_lock, flags);
> +
> + e = kzalloc(sizeof *e, GFP_KERNEL);
> + if (e == NULL) {
> + spin_lock_irqsave(&dev->event_lock, flags);
> + file_priv->event_space += sizeof e->event;
> + spin_unlock_irqrestore(&dev->event_lock, flags);
> + goto out;
> + }
> +
> + e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
> + e->event.base.length = sizeof e->event;
> + e->event.user_data = user_data;
> + e->base.event = &e->event.base;
> + e->base.file_priv = file_priv;
> + e->base.destroy =
> + (void (*) (struct drm_pending_event *)) kfree;
> +
> +out:
> + return e;
> +}
> +
> +static void destroy_vblank_event(struct drm_device *dev,
> + struct drm_file *file_priv, struct drm_pending_vblank_event *e)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&dev->event_lock, flags);
> + file_priv->event_space += sizeof e->event;
> + spin_unlock_irqrestore(&dev->event_lock, flags);
> + kfree(e);
> +}
> +
> /**
> * drm_mode_page_flip_ioctl - schedule an asynchronous fb update
> * @dev: DRM device
> @@ -4446,10 +4667,10 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
> void *data, struct drm_file *file_priv)
> {
> struct drm_mode_crtc_page_flip *page_flip = data;
> + struct drm_mode_config *config = &dev->mode_config;
> struct drm_crtc *crtc;
> - struct drm_framebuffer *fb = NULL, *old_fb = NULL;
> struct drm_pending_vblank_event *e = NULL;
> - unsigned long flags;
> + struct drm_atomic_state *state;
> int ret = -EINVAL;
>
> if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
> @@ -4463,92 +4684,41 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
> if (!crtc)
> return -ENOENT;
>
> - drm_modeset_lock(&crtc->mutex, NULL);
> - if (crtc->primary->fb == NULL) {
> - /* The framebuffer is currently unbound, presumably
> - * due to a hotplug event, that userspace has not
> - * yet discovered.
> - */
> - ret = -EBUSY;
> - goto out;
> - }
> -
> - if (crtc->funcs->page_flip == NULL)
> - goto out;
> -
> - fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
> - if (!fb) {
> - ret = -ENOENT;
> - goto out;
> - }
> -
> - ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb);
> - if (ret)
> - goto out;
> -
> - if (crtc->primary->fb->pixel_format != fb->pixel_format) {
> - DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
> - ret = -EINVAL;
> - goto out;
> - }
> +retry:
> + state = dev->driver->atomic_begin(dev,
> + page_flip->flags | DRM_MODE_ATOMIC_NONBLOCK);
> + if (IS_ERR(state))
> + return PTR_ERR(state);
>
> if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
> - ret = -ENOMEM;
> - spin_lock_irqsave(&dev->event_lock, flags);
> - if (file_priv->event_space < sizeof e->event) {
> - spin_unlock_irqrestore(&dev->event_lock, flags);
> + e = create_vblank_event(dev, file_priv, page_flip->user_data);
> + if (!e) {
> + ret = -ENOMEM;
> goto out;
> }
> - file_priv->event_space -= sizeof e->event;
> - spin_unlock_irqrestore(&dev->event_lock, flags);
> -
> - e = kzalloc(sizeof *e, GFP_KERNEL);
> - if (e == NULL) {
> - spin_lock_irqsave(&dev->event_lock, flags);
> - file_priv->event_space += sizeof e->event;
> - spin_unlock_irqrestore(&dev->event_lock, flags);
> + ret = dev->driver->atomic_set_event(dev, state, &crtc->base, e);
> + if (ret) {
> goto out;
> }
> -
> - e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
> - e->event.base.length = sizeof e->event;
> - e->event.user_data = page_flip->user_data;
> - e->base.event = &e->event.base;
> - e->base.file_priv = file_priv;
> - e->base.destroy =
> - (void (*) (struct drm_pending_event *)) kfree;
> }
>
> - old_fb = crtc->primary->fb;
> - ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
> - if (ret) {
> - if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
> - spin_lock_irqsave(&dev->event_lock, flags);
> - file_priv->event_space += sizeof e->event;
> - spin_unlock_irqrestore(&dev->event_lock, flags);
> - kfree(e);
> - }
> - /* Keep the old fb, don't unref it. */
> - old_fb = NULL;
> - } else {
> - /*
> - * Warn if the driver hasn't properly updated the crtc->fb
> - * field to reflect that the new framebuffer is now used.
> - * Failing to do so will screw with the reference counting
> - * on framebuffers.
> - */
> - WARN_ON(crtc->primary->fb != fb);
> - /* Unref only the old framebuffer. */
> - fb = NULL;
> - }
> + ret = drm_mode_plane_set_obj_prop(crtc->primary, state,
> + config->prop_fb_id, page_flip->fb_id, NULL);
> + if (ret)
> + goto out;
>
> -out:
> - if (fb)
> - drm_framebuffer_unreference(fb);
> - if (old_fb)
> - drm_framebuffer_unreference(old_fb);
> - drm_modeset_unlock(&crtc->mutex);
> + ret = dev->driver->atomic_check(dev, state);
> + if (ret)
> + goto out;
> +
> + ret = dev->driver->atomic_commit(dev, state);
>
> +out:
> + if (ret && e)
> + destroy_vblank_event(dev, file_priv, e);
> + dev->driver->atomic_end(dev, state);
> + if (ret == -EDEADLK)
> + goto retry;
> return ret;
> }
>
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index b73d3b0..4669e69 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -286,7 +286,7 @@ 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;
> + struct drm_atomic_state *state;
> int i;
>
> drm_warn_on_modeset_not_all_locked(dev);
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> index 2a56973..f3c7e77 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> @@ -14,6 +14,7 @@
>
> #include <drm/drmP.h>
> #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_atomic.h>
>
> #include "exynos_drm_crtc.h"
> #include "exynos_drm_drv.h"
> @@ -289,6 +290,10 @@ static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
> struct drm_device *dev = crtc->dev;
> struct exynos_drm_private *dev_priv = dev->dev_private;
> struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
> + struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
> +
> + if (IS_ERR(cstate))
> + return PTR_ERR(cstate);
>
> if (property == dev_priv->crtc_mode_property) {
> enum exynos_crtc_mode mode = val;
> @@ -313,7 +318,7 @@ static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
> return 0;
> }
>
> - return -EINVAL;
> + return drm_crtc_set_property(crtc, cstate, property, val, blob_data);
> }
>
> static struct drm_crtc_funcs exynos_crtc_funcs = {
> diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
> index 6672732..5b6eee9 100644
> --- a/drivers/gpu/drm/gma500/cdv_intel_display.c
> +++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
> @@ -989,6 +989,7 @@ const struct drm_crtc_funcs cdv_intel_crtc_funcs = {
> .cursor_move = gma_crtc_cursor_move,
> .gamma_set = gma_crtc_gamma_set,
> .set_config = gma_crtc_set_config,
> + .set_property = drm_atomic_crtc_set_property,
> .destroy = gma_crtc_destroy,
> };
>
> diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
> index 87b50ba..79b5692 100644
> --- a/drivers/gpu/drm/gma500/psb_intel_display.c
> +++ b/drivers/gpu/drm/gma500/psb_intel_display.c
> @@ -444,6 +444,7 @@ const struct drm_crtc_funcs psb_intel_crtc_funcs = {
> .cursor_move = gma_crtc_cursor_move,
> .gamma_set = gma_crtc_gamma_set,
> .set_config = gma_crtc_set_config,
> + .set_property = drm_atomic_crtc_set_property,
> .destroy = gma_crtc_destroy,
> };
>
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index e9f6eb7..53b996f 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -10430,6 +10430,7 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
> .cursor_move = intel_crtc_cursor_move,
> .gamma_set = intel_crtc_gamma_set,
> .set_config = intel_crtc_set_config,
> + .set_property = drm_atomic_crtc_set_property,
> .destroy = intel_crtc_destroy,
> .page_flip = intel_crtc_page_flip,
> };
> diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
> index a034ed4..ba9bd91 100644
> --- a/drivers/gpu/drm/mgag200/mgag200_mode.c
> +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
> @@ -1296,6 +1296,7 @@ static const struct drm_crtc_funcs mga_crtc_funcs = {
> .cursor_move = mga_crtc_cursor_move,
> .gamma_set = mga_crtc_gamma_set,
> .set_config = drm_crtc_helper_set_config,
> + .set_property = drm_atomic_crtc_set_property,
> .destroy = mga_crtc_destroy,
> };
>
> diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> index 7cf0f78..d0d8befd 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
> @@ -471,8 +471,10 @@ static int mdp4_crtc_set_property(struct drm_crtc *crtc,
> struct drm_atomic_state *state, struct drm_property *property,
> uint64_t val, void *blob_data)
> {
> - // XXX
> - return -EINVAL;
> + struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
> + if (IS_ERR(cstate))
> + return PTR_ERR(cstate);
> + return drm_crtc_set_property(crtc, cstate, property, val, blob_data);
> }
>
> #define CURSOR_WIDTH 64
> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> index 771390b..7f4ee99 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
> @@ -389,8 +389,10 @@ static int mdp5_crtc_set_property(struct drm_crtc *crtc,
> struct drm_atomic_state *state, struct drm_property *property,
> uint64_t val, void *blob_data)
> {
> - // XXX
> - return -EINVAL;
> + struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
> + if (IS_ERR(cstate))
> + return PTR_ERR(cstate);
> + return drm_crtc_set_property(crtc, cstate, property, val, blob_data);
> }
>
> static const struct drm_crtc_funcs mdp5_crtc_funcs = {
> diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> index 41be342..9e24632 100644
> --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
> @@ -1086,6 +1086,7 @@ static const struct drm_crtc_funcs nv04_crtc_funcs = {
> .cursor_move = nv04_crtc_cursor_move,
> .gamma_set = nv_crtc_gamma_set,
> .set_config = nouveau_crtc_set_config,
> + .set_property = drm_atomic_crtc_set_property,
> .page_flip = nouveau_crtc_page_flip,
> .destroy = nv_crtc_destroy,
> };
> diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
> index 58af547..ecbffeb 100644
> --- a/drivers/gpu/drm/nouveau/nv50_display.c
> +++ b/drivers/gpu/drm/nouveau/nv50_display.c
> @@ -1329,6 +1329,7 @@ static const struct drm_crtc_funcs nv50_crtc_func = {
> .cursor_move = nv50_crtc_cursor_move,
> .gamma_set = nv50_crtc_gamma_set,
> .set_config = nouveau_crtc_set_config,
> + .set_property = drm_atomic_crtc_set_property,
> .destroy = nv50_crtc_destroy,
> .page_flip = nouveau_crtc_page_flip,
> };
> diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
> index a75934d..772687b 100644
> --- a/drivers/gpu/drm/omapdrm/omap_crtc.c
> +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
> @@ -387,14 +387,22 @@ static int omap_crtc_set_property(struct drm_crtc *crtc,
> {
> struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
> struct omap_drm_private *priv = crtc->dev->dev_private;
> + struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
> + int ret;
> +
> + if (IS_ERR(cstate))
> + return PTR_ERR(cstate);
>
> if (property == priv->rotation_prop) {
> - crtc->invert_dimensions =
> + cstate->invert_dimensions =
> !!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
> }
>
> - return omap_plane_set_property(omap_crtc->plane, state,
> + ret = omap_plane_set_property(omap_crtc->plane, state,
> property, val, blob_data);
> + if (ret)
> + ret = drm_crtc_set_property(crtc, cstate, property, val, blob_data);
> + return ret;
> }
>
> static const struct drm_crtc_funcs omap_crtc_funcs = {
> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
> index da80bdc..3f64c47 100644
> --- a/drivers/gpu/drm/omapdrm/omap_drv.c
> +++ b/drivers/gpu/drm/omapdrm/omap_drv.c
> @@ -579,7 +579,7 @@ static void dev_lastclose(struct drm_device *dev)
> */
> for (i = 0; i < priv->num_crtcs; i++) {
> drm_object_property_set_value(&priv->crtcs[i]->base,
> - &priv->crtcs[i]->propvals,
> + &priv->crtcs[i]->state->propvals,
> priv->rotation_prop, 0, NULL);
> }
>
> diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
> index b54c970..25896a9 100644
> --- a/drivers/gpu/drm/qxl/qxl_display.c
> +++ b/drivers/gpu/drm/qxl/qxl_display.c
> @@ -29,6 +29,7 @@
> #include "qxl_drv.h"
> #include "qxl_object.h"
> #include "drm_crtc_helper.h"
> +#include "drm_atomic.h"
>
> static bool qxl_head_enabled(struct qxl_head *head)
> {
> @@ -373,6 +374,7 @@ static const struct drm_crtc_funcs qxl_crtc_funcs = {
> .cursor_set2 = qxl_crtc_cursor_set2,
> .cursor_move = qxl_crtc_cursor_move,
> .set_config = drm_crtc_helper_set_config,
> + .set_property = drm_atomic_crtc_set_property,
> .destroy = qxl_crtc_destroy,
> };
>
> diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
> index 8d99d5e..cc86aac 100644
> --- a/drivers/gpu/drm/radeon/radeon_display.c
> +++ b/drivers/gpu/drm/radeon/radeon_display.c
> @@ -32,6 +32,7 @@
>
> #include <linux/pm_runtime.h>
> #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_atomic.h>
> #include <drm/drm_edid.h>
>
> #include <linux/gcd.h>
> @@ -546,6 +547,7 @@ static const struct drm_crtc_funcs radeon_crtc_funcs = {
> .cursor_move = radeon_crtc_cursor_move,
> .gamma_set = radeon_crtc_gamma_set,
> .set_config = radeon_crtc_set_config,
> + .set_property = drm_atomic_crtc_set_property,
> .destroy = radeon_crtc_destroy,
> .page_flip = radeon_crtc_page_flip,
> };
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> index 299267d..f5a3d55 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -17,6 +17,7 @@
> #include <drm/drmP.h>
> #include <drm/drm_crtc.h>
> #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_atomic.h>
> #include <drm/drm_fb_cma_helper.h>
> #include <drm/drm_gem_cma_helper.h>
>
> @@ -527,6 +528,7 @@ static int rcar_du_crtc_page_flip(struct drm_crtc *crtc,
> static const struct drm_crtc_funcs crtc_funcs = {
> .destroy = drm_crtc_cleanup,
> .set_config = drm_crtc_helper_set_config,
> + .set_property = drm_atomic_crtc_set_property,
> .page_flip = rcar_du_crtc_page_flip,
> };
>
> diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> index 90e023a..0a5280c 100644
> --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> @@ -17,6 +17,7 @@
> #include <drm/drmP.h>
> #include <drm/drm_crtc.h>
> #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_atomic.h>
> #include <drm/drm_fb_cma_helper.h>
> #include <drm/drm_gem_cma_helper.h>
>
> @@ -506,6 +507,7 @@ static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc,
> static const struct drm_crtc_funcs crtc_funcs = {
> .destroy = drm_crtc_cleanup,
> .set_config = drm_crtc_helper_set_config,
> + .set_property = drm_atomic_crtc_set_property,
> .page_flip = shmob_drm_crtc_page_flip,
> };
>
> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> index 92839ba..b07f116 100644
> --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> @@ -411,6 +411,7 @@ static int tilcdc_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
> static const struct drm_crtc_funcs tilcdc_crtc_funcs = {
> .destroy = tilcdc_crtc_destroy,
> .set_config = drm_crtc_helper_set_config,
> + .set_property = drm_atomic_crtc_set_property,
> .page_flip = tilcdc_crtc_page_flip,
> };
>
> diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
> index cddc4fc..36d0116 100644
> --- a/drivers/gpu/drm/udl/udl_modeset.c
> +++ b/drivers/gpu/drm/udl/udl_modeset.c
> @@ -14,6 +14,7 @@
> #include <drm/drmP.h>
> #include <drm/drm_crtc.h>
> #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_atomic.h>
> #include "udl_drv.h"
>
> /*
> @@ -383,6 +384,7 @@ static struct drm_crtc_helper_funcs udl_helper_funcs = {
>
> static const struct drm_crtc_funcs udl_crtc_funcs = {
> .set_config = drm_crtc_helper_set_config,
> + .set_property = drm_atomic_crtc_set_property,
> .destroy = udl_crtc_destroy,
> };
>
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> index b2b9bd2..0313b00 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> @@ -300,6 +300,7 @@ static struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
> .cursor_move = vmw_du_crtc_cursor_move,
> .gamma_set = vmw_du_crtc_gamma_set,
> .destroy = vmw_ldu_crtc_destroy,
> + .set_property = drm_atomic_crtc_set_property,
> .set_config = vmw_ldu_crtc_set_config,
> };
>
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> index a95d3a0..b723e09 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> @@ -397,6 +397,7 @@ static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
> .gamma_set = vmw_du_crtc_gamma_set,
> .destroy = vmw_sou_crtc_destroy,
> .set_config = vmw_sou_crtc_set_config,
> + .set_property = drm_atomic_crtc_set_property,
> .page_flip = vmw_du_page_flip,
> };
>
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index 78e93ec..7946b7f 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -70,6 +70,9 @@
> struct drm_atomic_funcs {
> 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);
> +
> + int (*check_crtc_state)(struct drm_crtc *crtc, struct drm_crtc_state *cstate);
> + int (*commit_crtc_state)(struct drm_crtc *crtc, struct drm_crtc_state *cstate);
> };
>
> const extern struct drm_atomic_funcs drm_atomic_funcs;
> @@ -109,6 +112,30 @@ drm_atomic_commit_plane_state(struct drm_plane *plane,
> return funcs->commit_plane_state(plane, pstate);
> }
>
> +int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
> + struct drm_atomic_state *state, struct drm_property *property,
> + uint64_t val, void *blob_data);
> +struct drm_crtc_state *drm_atomic_get_crtc_state(struct drm_crtc *crtc,
> + struct drm_atomic_state *state);
> +
> +static inline int
> +drm_atomic_check_crtc_state(struct drm_crtc *crtc,
> + struct drm_crtc_state *cstate)
> +{
> + const struct drm_atomic_funcs *funcs =
> + crtc->dev->driver->atomic_funcs;
> + return funcs->check_crtc_state(crtc, cstate);
> +}
> +
> +static inline int
> +drm_atomic_commit_crtc_state(struct drm_crtc *crtc,
> + struct drm_crtc_state *cstate)
> +{
> + const struct drm_atomic_funcs *funcs =
> + crtc->dev->driver->atomic_funcs;
> + return funcs->commit_crtc_state(crtc, cstate);
> +}
> +
> /**
> * struct drm_atomic_state - the state object used by atomic helpers
> */
> @@ -118,6 +145,8 @@ struct drm_atomic_state {
> uint32_t flags;
> struct drm_plane **planes;
> struct drm_plane_state **pstates;
> + struct drm_crtc **crtcs;
> + struct drm_crtc_state **cstates;
>
> bool committed;
> bool checked; /* just for debugging */
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 58309cc..2fbf13a 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -284,6 +284,10 @@ struct drm_crtc_funcs {
> struct drm_pending_vblank_event *event,
> uint32_t flags);
>
> + struct drm_crtc_state *(*create_state)(struct drm_crtc *crtc);
> + void (*destroy_state)(struct drm_crtc *crtc,
> + struct drm_crtc_state *cstate);
> +
> int (*set_property)(struct drm_crtc *crtc,
> struct drm_atomic_state *state,
> struct drm_property *property, uint64_t val,
> @@ -291,21 +295,52 @@ struct drm_crtc_funcs {
> };
>
> /**
> + * drm_crtc_state - mutable crtc state
> + * @invert_dimensions: for purposes of error checking crtc vs fb sizes,
> + * invert the width/height of the crtc. This is used if the driver
> + * is performing 90 or 270 degree rotated scanout
> + * @mode_valid: a valid mode has been set
> + * @set_config: needs modeset (crtc->set_config())
> + * @connectors_change: the connector-ids array has changed
> + * @num_connector_ids: the number of connector-ids
> + * @connector_ids: array of connector ids
> + * @mode: current mode timings
> + * @event: pending pageflip event
> + * @propvals: property values
> + * @state: current global/toplevel state object (for atomic) while an
> + * update is in progress, NULL otherwise.
> + */
> +struct drm_crtc_state {
> + bool invert_dimensions : 1;
> + bool mode_valid : 1;
> +
> + /* transient state, only valid during atomic operation: */
> + bool set_config : 1;
> + bool connectors_change : 1;
> +
> + uint8_t num_connector_ids;
> + uint32_t *connector_ids;
> + struct drm_mode_modeinfo mode;
> +
> + struct drm_pending_vblank_event *event;
> +
> + struct drm_object_property_values propvals;
> +
> + struct drm_atomic_state *state;
> +};
> +
> +/**
> * drm_crtc - central CRTC control structure
> * @dev: parent DRM device
> * @head: list management
> + * @id: CRTC number, 0..n
> * @mutex: per-CRTC locking
> * @base: base KMS object for ID tracking etc.
> * @primary: primary plane for this CRTC
> * @cursor: cursor plane for this CRTC
> + * @state: the mutable state
> * @enabled: is this CRTC enabled?
> - * @mode: current mode timings
> * @hwmode: mode timings as programmed to hw regs
> - * @invert_dimensions: for purposes of error checking crtc vs fb sizes,
> - * invert the width/height of the crtc. This is used if the driver
> - * is performing 90 or 270 degree rotated scanout
> - * @x: x position on screen
> - * @y: y position on screen
> * @funcs: CRTC control functions
> * @gamma_size: size of gamma ramp
> * @gamma_store: gamma ramp values
> @@ -322,6 +357,8 @@ struct drm_crtc {
> struct drm_device *dev;
> struct list_head head;
>
> + int id;
> +
> /**
> * crtc mutex
> *
> @@ -337,23 +374,19 @@ struct drm_crtc {
> struct drm_plane *primary;
> struct drm_plane *cursor;
>
> + struct drm_crtc_state *state;
> +
> /* Temporary tracking of the old fb while a modeset is ongoing. Used
> * by drm_mode_set_config_internal to implement correct refcounting. */
> struct drm_framebuffer *old_fb;
>
> bool enabled;
>
> - /* Requested mode from modesetting. */
> - struct drm_display_mode mode;
> -
> /* Programmed mode in hw, after adjustments for encoders,
> * crtc, panel scaling etc. Needed for timestamping etc.
> */
> struct drm_display_mode hwmode;
>
> - bool invert_dimensions;
> -
> - int x, y;
> const struct drm_crtc_funcs *funcs;
>
> /* CRTC gamma size for reporting to userspace */
> @@ -367,9 +400,15 @@ struct drm_crtc {
> void *helper_private;
>
> struct drm_object_properties properties;
> - struct drm_object_property_values propvals;
> -};
>
> + /* These are (temporary) duplicate information from what is in the
> + * drm_crtc_state struct.. keeping duplicate copy here makes the
> + * switch to atomic far less intrusive. Once all the drivers and
> + * the crtc/fb helpers are updated, then we can remove these:
> + */
> + int x, y;
> + struct drm_display_mode mode;
> +};
>
> /**
> * drm_connector_funcs - control connectors on a given device
> @@ -875,6 +914,8 @@ struct drm_mode_config {
> struct drm_property *prop_crtc_h;
> struct drm_property *prop_fb_id;
> struct drm_property *prop_crtc_id;
> + struct drm_property *prop_connector_ids;
> + struct drm_property *prop_mode;
> struct drm_property *edid_property;
> struct drm_property *dpms_property;
> struct drm_property *plane_type_property;
> @@ -935,7 +976,8 @@ extern int drm_crtc_init(struct drm_device *dev,
> struct drm_crtc *crtc,
> const struct drm_crtc_funcs *funcs);
> extern void drm_crtc_cleanup(struct drm_crtc *crtc);
> -extern unsigned int drm_crtc_index(struct drm_crtc *crtc);
> +struct drm_display_mode *drm_crtc_get_mode(struct drm_crtc *crtc,
> + struct drm_crtc_state *cstate);
>
> /**
> * drm_crtc_mask - find the mask of a registered CRTC
> @@ -946,9 +988,18 @@ extern unsigned int drm_crtc_index(struct drm_crtc *crtc);
> */
> static inline uint32_t drm_crtc_mask(struct drm_crtc *crtc)
> {
> - return 1 << drm_crtc_index(crtc);
> + return 1 << crtc->id;
> }
>
> +extern int drm_crtc_check_state(struct drm_crtc *crtc,
> + struct drm_crtc_state *state);
> +extern void drm_crtc_commit_state(struct drm_crtc *crtc,
> + struct drm_crtc_state *state);
> +extern int drm_crtc_set_property(struct drm_crtc *crtc,
> + struct drm_crtc_state *state,
> + struct drm_property *property,
> + uint64_t value, void *blob_data);
> +
> extern void drm_connector_ida_init(void);
> extern void drm_connector_ida_destroy(void);
> extern int drm_connector_init(struct drm_device *dev,
> @@ -1024,6 +1075,7 @@ extern const char *drm_get_tv_select_name(int val);
> extern void drm_fb_release(struct drm_file *file_priv);
> extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group);
> extern void drm_mode_group_destroy(struct drm_mode_group *group);
> +extern int drm_crtc_convert_umode(struct drm_display_mode *out, const struct drm_mode_modeinfo *in);
> extern bool drm_probe_ddc(struct i2c_adapter *adapter);
> extern struct edid *drm_get_edid(struct drm_connector *connector,
> struct i2c_adapter *adapter);
> @@ -1251,6 +1303,25 @@ drm_property_blob_find(struct drm_device *dev, uint32_t id)
> return mo ? obj_to_blob(mo) : NULL;
> }
>
> +static inline struct drm_crtc_state *
> +drm_crtc_create_state(struct drm_crtc *crtc)
> +{
> + if (crtc->funcs->create_state)
> + return crtc->funcs->create_state(crtc);
> + return kzalloc(sizeof(struct drm_crtc_state), GFP_KERNEL);
> +}
> +
> +static inline void
> +drm_crtc_destroy_state(struct drm_crtc *crtc,
> + struct drm_crtc_state *cstate)
> +{
> + kfree(cstate->connector_ids);
> + if (crtc->funcs->destroy_state)
> + crtc->funcs->destroy_state(crtc, cstate);
> + else
> + kfree(cstate);
> +}
> +
> static inline struct drm_plane_state *
> drm_plane_create_state(struct drm_plane *plane)
> {
> --
> 1.9.0
>
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
next prev parent reply other threads:[~2014-05-26 9:31 UTC|newest]
Thread overview: 69+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-05-24 18:30 [PATCH 00/17] prepare for atomic/nuclear modeset/pageflip Rob Clark
2014-05-24 18:30 ` [PATCH 01/17] drm: fix typo Rob Clark
2014-05-24 18:30 ` [PATCH 02/17] drm: add atomic fxns Rob Clark
2014-05-24 18:30 ` [PATCH 03/17] drm: convert crtc and mode_config to ww_mutex Rob Clark
2014-05-25 22:10 ` Daniel Vetter
2014-05-25 23:16 ` Rob Clark
2014-05-26 8:23 ` Daniel Vetter
2014-05-26 11:56 ` Rob Clark
2014-05-26 14:35 ` Daniel Vetter
2014-05-26 14:36 ` Daniel Vetter
2014-05-26 15:04 ` Rob Clark
2014-05-26 15:07 ` Daniel Vetter
2014-05-26 15:20 ` Rob Clark
2014-05-26 15:35 ` Daniel Vetter
2014-05-26 15:49 ` Rob Clark
2014-05-26 16:09 ` Daniel Vetter
2014-05-24 18:30 ` [PATCH 04/17] drm: add object property type Rob Clark
2014-05-26 8:29 ` Daniel Vetter
2014-05-26 8:33 ` Daniel Vetter
2014-05-26 11:06 ` Rob Clark
2014-05-24 18:30 ` [PATCH 05/17] drm: add signed-range " Rob Clark
2014-05-24 18:30 ` [PATCH 06/17] drm: helpers to find mode objects Rob Clark
2014-05-26 8:37 ` Daniel Vetter
2014-05-26 8:55 ` Daniel Vetter
2014-05-26 11:12 ` Rob Clark
2014-05-24 18:30 ` [PATCH 07/17] drm: split propvals out and blob property support Rob Clark
2014-05-24 18:30 ` [PATCH 08/17] drm: Allow drm_mode_object_find() to look up an object of any type Rob Clark
2014-05-24 18:30 ` [PATCH 09/17] drm: Refactor object property check code Rob Clark
2014-05-24 18:30 ` [PATCH 10/17] drm: allow FB's in drm_mode_object_find Rob Clark
2014-05-26 8:39 ` Daniel Vetter
2014-05-24 18:30 ` [PATCH 11/17] drm: convert plane to properties/state Rob Clark
2014-05-26 9:12 ` Daniel Vetter
2014-05-26 11:32 ` Rob Clark
2014-05-26 14:52 ` Daniel Vetter
2014-05-24 18:30 ` [PATCH 12/17] drm: convert crtc " Rob Clark
2014-05-26 9:31 ` Daniel Vetter [this message]
2014-05-26 11:35 ` Rob Clark
2014-05-26 14:56 ` Daniel Vetter
2014-05-26 15:15 ` Rob Clark
2014-05-26 15:23 ` Ville Syrjälä
2014-05-26 15:37 ` Daniel Vetter
2014-05-26 15:42 ` Rob Clark
2014-05-26 15:46 ` Ville Syrjälä
2014-05-26 16:12 ` Daniel Vetter
2014-05-24 18:30 ` [PATCH 13/17] drm: push locking down into restore_fbdev_mode Rob Clark
2014-05-26 9:34 ` Daniel Vetter
2014-05-24 18:30 ` [PATCH 14/17] drm/msm: add atomic support Rob Clark
2014-05-26 17:54 ` Daniel Vetter
2014-05-27 15:58 ` Rob Clark
2014-05-27 17:50 ` Daniel Vetter
2014-05-27 18:48 ` Rob Clark
2014-05-27 19:26 ` Daniel Vetter
2014-05-27 20:06 ` Rob Clark
2014-05-27 22:09 ` Daniel Vetter
2014-05-27 23:32 ` Rob Clark
2014-05-28 13:21 ` Daniel Vetter
2014-05-28 14:14 ` Ville Syrjälä
2014-05-28 14:50 ` Daniel Vetter
2014-05-28 15:19 ` Rob Clark
2014-05-27 23:47 ` Rob Clark
2014-05-28 13:32 ` Daniel Vetter
2014-05-24 18:30 ` [PATCH 15/17] drm: spiff out FB refcnting traces Rob Clark
2014-05-24 18:30 ` [PATCH 16/17] drm: more conservative locking Rob Clark
2014-05-24 18:30 ` [PATCH 17/17] drm: Fix up the atomic legacy paths so they work Rob Clark
2014-05-26 10:40 ` [PATCH 00/17] prepare for atomic/nuclear modeset/pageflip Daniel Vetter
2014-05-26 12:48 ` Rob Clark
2014-05-26 15:24 ` Daniel Vetter
2014-05-26 16:12 ` Rob Clark
2014-05-26 17:36 ` Daniel Vetter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20140526093110.GC14357@phenom.ffwll.local \
--to=daniel@ffwll.ch \
--cc=dri-devel@lists.freedesktop.org \
--cc=robdclark@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.