From: Rob Clark <robdclark@gmail.com>
To: dri-devel@lists.freedesktop.org
Subject: [PATCH 5/7] drm: convert crtc to properties/state
Date: Fri, 30 May 2014 13:23:07 -0400 [thread overview]
Message-ID: <1401470589-596-6-git-send-email-robdclark@gmail.com> (raw)
In-Reply-To: <1401470589-596-1-git-send-email-robdclark@gmail.com>
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>
---
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 | 631 +++++++++++++++++++----------
drivers/gpu/drm/drm_fb_helper.c | 24 +-
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, 837 insertions(+), 246 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 ac12d9b..00b1c13 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -49,11 +49,13 @@ struct drm_atomic_state *drm_atomic_begin(struct drm_device *dev,
struct drm_atomic_state *state;
uint32_t acquire_flags = 0;
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);
@@ -78,6 +80,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);
@@ -96,7 +104,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;
+ }
}
EXPORT_SYMBOL(drm_atomic_set_event);
@@ -115,6 +134,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++) {
@@ -124,6 +144,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;
@@ -207,6 +234,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++) {
@@ -217,6 +245,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);
@@ -227,8 +263,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) {
@@ -407,6 +453,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;
@@ -429,8 +476,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,
@@ -447,7 +497,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
@@ -477,9 +527,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)
@@ -488,8 +539,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);
+ }
+ 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 a9ecf52..8024add 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -685,10 +685,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));
@@ -708,7 +705,9 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
* in this manner.
*/
if (atomic_read(&fb->refcount.refcount) > 1) {
- void *state;
+ struct drm_mode_config *config = &dev->mode_config;
+ struct drm_atomic_state *state;
+ int ret;
state = dev->driver->atomic_begin(dev, 0);
if (IS_ERR(state)) {
@@ -716,24 +715,15 @@ 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);
- }
- }
+retry:
+ ret = drm_modeset_lock(&config->connection_mutex, &state->acquire_ctx);
+ if (ret)
+ goto out;
+ ret = drm_modeset_lock_all_crtcs(dev, &state->acquire_ctx);
+ if (ret)
+ goto out;
+ /* 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);
@@ -745,9 +735,12 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
else
dev->driver->atomic_commit(dev, state);
+out:
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&state->acquire_ctx);
+ goto retry;
+ }
dev->driver->atomic_end(dev, state);
-
- drm_modeset_unlock_all(dev);
}
drm_framebuffer_unreference(fb);
@@ -778,9 +771,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);
@@ -792,14 +789,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, &config->crtc_list);
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);
@@ -828,31 +828,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);
+}
+
+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_index);
+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
@@ -1262,6 +1476,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;
@@ -1488,6 +1706,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;
}
@@ -1777,7 +2005,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)
@@ -2024,8 +2252,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;
@@ -2528,7 +2756,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 ||
@@ -2537,7 +2765,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;
}
@@ -2564,22 +2792,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);
@@ -2597,55 +2818,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;
- }
-
- ret = drm_crtc_convert_umode(mode, &crtc_req->mode);
- if (ret) {
- DRM_DEBUG_KMS("Invalid mode\n");
- goto out;
+ fb_id = crtc_req->fb_id;
}
-
- 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) {
@@ -2653,52 +2834,75 @@ 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);
+ state = dev->driver->atomic_begin(dev, 0);
+ if (IS_ERR(state))
+ return PTR_ERR(state);
-out:
- if (fb)
- drm_framebuffer_unreference(fb);
+retry:
+ ret = drm_modeset_lock(&config->connection_mutex, &state->acquire_ctx);
+ if (ret)
+ goto out;
+ ret = drm_modeset_lock_all_crtcs(dev, &state->acquire_ctx);
+ if (ret)
+ goto out;
- kfree(connector_set);
- drm_mode_destroy(dev, mode);
- drm_modeset_unlock_all(dev);
+ /* 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;
+
+ 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) {
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&state->acquire_ctx);
+ goto retry;
+ }
+ dev->driver->atomic_end(dev, state);
+ }
return ret;
}
@@ -4070,9 +4274,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;
}
@@ -4245,11 +4446,11 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
-retry:
state = dev->driver->atomic_begin(dev, 0);
if (IS_ERR(state))
return PTR_ERR(state);
+retry:
ret = drm_modeset_lock(&config->connection_mutex, &state->acquire_ctx);
if (ret)
goto out;
@@ -4270,9 +4471,11 @@ retry:
ret = dev->driver->atomic_commit(dev, state);
out:
- dev->driver->atomic_end(dev, state);
- if (ret == -EDEADLK)
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&state->acquire_ctx);
goto retry;
+ }
+ dev->driver->atomic_end(dev, state);
return ret;
}
@@ -4464,6 +4667,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
@@ -4486,10 +4734,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 ||
@@ -4503,92 +4751,43 @@ 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;
- }
+ state = dev->driver->atomic_begin(dev,
+ page_flip->flags | DRM_MODE_ATOMIC_NONBLOCK);
+ if (IS_ERR(state))
+ return PTR_ERR(state);
+retry:
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);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&state->acquire_ctx);
+ goto retry;
+ }
+ dev->driver->atomic_end(dev, state);
return ret;
}
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index d88a196..969c495 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -36,6 +36,7 @@
#include <linux/module.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_atomic.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
@@ -277,10 +278,11 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper,
bool lockless)
{
struct drm_device *dev = fb_helper->dev;
+ struct drm_mode_config *config = &dev->mode_config;
struct drm_plane *plane;
bool error = false;
- void *state;
- int i;
+ struct drm_atomic_state *state;
+ int ret, i;
state = dev->driver->atomic_begin(dev, lockless ?
DRM_MODE_ATOMIC_NOLOCK : 0);
@@ -289,6 +291,14 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper,
return true;
}
+retry:
+ ret = drm_modeset_lock(&config->connection_mutex, &state->acquire_ctx);
+ if (ret)
+ goto out;
+ ret = drm_modeset_lock_all_crtcs(dev, &state->acquire_ctx);
+ if (ret)
+ goto out;
+
list_for_each_entry(plane, &dev->mode_config.plane_list, head)
if (plane->type != DRM_PLANE_TYPE_PRIMARY)
drm_plane_force_disable(plane, state);
@@ -299,8 +309,15 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper,
else
dev->driver->atomic_commit(dev, state);
+out:
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&state->acquire_ctx);
+ goto retry;
+ }
dev->driver->atomic_end(dev, state);
+ drm_modeset_lock_all(dev);
+
for (i = 0; i < fb_helper->crtc_count; i++) {
struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
struct drm_crtc *crtc = mode_set->crtc;
@@ -316,6 +333,9 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper,
if (ret)
error = true;
}
+
+ drm_modeset_unlock_all(dev);
+
return error;
}
/**
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 fdc58fa..ea9307d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10454,6 +10454,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 efa19c8..8d9b604 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 ff48944..57b67b4 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 9630a32..4b4bc42 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 d642d4a0..95ffae7 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 784eb62..5f4e786 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
@@ -876,6 +915,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;
@@ -936,7 +977,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
@@ -947,9 +989,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,
@@ -1025,6 +1076,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);
@@ -1252,6 +1304,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.3
next prev parent reply other threads:[~2014-05-30 17:23 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-05-30 17:23 [PATCH 0/7] prepare for atomic/nuclear modeset/pageflip (vN+1) Rob Clark
2014-05-30 17:23 ` [PATCH 1/7] drm: add atomic fxns Rob Clark
2014-05-30 17:23 ` [PATCH 2/7] drm: split propvals out and blob property support Rob Clark
2014-05-30 17:23 ` [PATCH 3/7] drm: Refactor object property check code Rob Clark
2014-05-30 17:23 ` [PATCH 4/7] drm: convert plane to properties/state Rob Clark
2014-05-30 17:23 ` Rob Clark [this message]
2014-05-30 17:23 ` [PATCH 6/7] drm/msm: add atomic support Rob Clark
2014-05-30 17:23 ` [PATCH 7/7] drm: Fix up the atomic legacy paths so they work Rob Clark
-- strict thread matches above, loose matches on Subject: below --
2014-07-23 19:38 [PATCH 0/7] prepare for atomic.. the great propertyification Rob Clark
2014-07-23 19:38 ` [PATCH 5/7] drm: convert crtc to properties/state Rob Clark
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=1401470589-596-6-git-send-email-robdclark@gmail.com \
--to=robdclark@gmail.com \
--cc=dri-devel@lists.freedesktop.org \
/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.