[RFCv4 09/14] drm: convert plane to properties/state
Rob Clark
robdclark at gmail.com
Mon Nov 25 06:47:33 PST 2013
Break the mutable state of a plane out into a separate structure
and use atomic properties mechanism to set plane attributes. This
makes it easier to have some helpers for plane->set_property()
and for checking for invalid params. The idea is that individual
drivers can wrap the state struct in their own struct which adds
driver specific parameters, for easy build-up of state across
multiple set_property() calls and for easy atomic commit or roll-
back.
The same should be done for CRTC, encoder, and connector, but this
patch only includes the first part (plane).
---
drivers/gpu/drm/drm_atomic_helper.c | 156 ++++++++++-
drivers/gpu/drm/drm_crtc.c | 397 +++++++++++++++++++---------
drivers/gpu/drm/drm_fb_helper.c | 17 +-
drivers/gpu/drm/exynos/exynos_drm_crtc.c | 4 +-
drivers/gpu/drm/exynos/exynos_drm_encoder.c | 6 +-
drivers/gpu/drm/exynos/exynos_drm_plane.c | 15 +-
drivers/gpu/drm/i915/intel_sprite.c | 21 +-
drivers/gpu/drm/msm/mdp4/mdp4_crtc.c | 2 +-
drivers/gpu/drm/msm/mdp4/mdp4_plane.c | 19 +-
drivers/gpu/drm/nouveau/dispnv04/overlay.c | 8 +-
drivers/gpu/drm/omapdrm/omap_crtc.c | 4 +-
drivers/gpu/drm/omapdrm/omap_drv.c | 2 +-
drivers/gpu/drm/omapdrm/omap_plane.c | 33 ++-
drivers/gpu/drm/rcar-du/rcar_du_plane.c | 8 +-
drivers/gpu/drm/shmobile/shmob_drm_crtc.c | 2 +-
drivers/gpu/drm/shmobile/shmob_drm_plane.c | 6 +-
drivers/gpu/drm/tegra/dc.c | 16 +-
include/drm/drm_atomic_helper.h | 39 ++-
include/drm/drm_crtc.h | 88 +++++-
19 files changed, 654 insertions(+), 189 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 8b37cf1..14e0571 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -39,10 +39,12 @@
void *drm_atomic_helper_begin(struct drm_device *dev, uint32_t flags)
{
struct drm_atomic_helper_state *state;
+ int nplanes = dev->mode_config.num_plane;
int sz;
void *ptr;
sz = sizeof(*state);
+ sz += (sizeof(state->planes) + sizeof(state->pstates)) * nplanes;
ptr = kzalloc(sz, GFP_KERNEL);
@@ -57,6 +59,12 @@ void *drm_atomic_helper_begin(struct drm_device *dev, uint32_t flags)
state->dev = dev;
state->flags = flags;
+ state->planes = ptr;
+ ptr = &state->planes[nplanes];
+
+ state->pstates = ptr;
+ ptr = &state->pstates[nplanes];
+
return state;
}
EXPORT_SYMBOL(drm_atomic_helper_begin);
@@ -92,7 +100,19 @@ EXPORT_SYMBOL(drm_atomic_helper_set_event);
*/
int drm_atomic_helper_check(struct drm_device *dev, void *state)
{
- return 0; /* for now */
+ struct drm_atomic_helper_state *a = state;
+ int nplanes = dev->mode_config.num_plane;
+ int i, ret = 0;
+
+ for (i = 0; i < nplanes; i++) {
+ if (a->planes[i]) {
+ ret = drm_atomic_check_plane_state(a->planes[i], a->pstates[i]);
+ if (ret)
+ break;
+ }
+ }
+
+ return ret;
}
EXPORT_SYMBOL(drm_atomic_helper_check);
@@ -168,6 +188,18 @@ fail:
static void commit_locks(struct drm_atomic_helper_state *a,
struct ww_acquire_ctx *ww_ctx)
{
+ struct drm_device *dev = a->dev;
+ int nplanes = dev->mode_config.num_plane;
+ int i;
+
+ for (i = 0; i < nplanes; i++) {
+ struct drm_plane *plane = a->planes[i];
+ if (plane) {
+ plane->state->state = NULL;
+ drm_atomic_helper_destroy_plane_state(plane, a->pstates[i]);
+ }
+ }
+
/* and properly release them (clear in_atomic, remove from list): */
mutex_lock(&a->mutex);
while (!list_empty(&a->locked)) {
@@ -186,7 +218,17 @@ static void commit_locks(struct drm_atomic_helper_state *a,
static int atomic_commit(struct drm_atomic_helper_state *a,
struct ww_acquire_ctx *ww_ctx)
{
- int ret = 0;
+ int nplanes = a->dev->mode_config.num_plane;
+ int i, ret = 0;
+
+ for (i = 0; i < nplanes; i++) {
+ struct drm_plane *plane = a->planes[i];
+ if (plane) {
+ ret = drm_atomic_commit_plane_state(plane, a->pstates[i]);
+ if (ret)
+ break;
+ }
+ }
commit_locks(a, ww_ctx);
@@ -263,7 +305,117 @@ void _drm_atomic_helper_state_free(struct kref *kref)
}
EXPORT_SYMBOL(_drm_atomic_helper_state_free);
+int drm_atomic_helper_plane_set_property(struct drm_plane *plane, void *state,
+ struct drm_property *property, uint64_t val, void *blob_data)
+{
+ struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+ if (IS_ERR(pstate))
+ return PTR_ERR(pstate);
+ return drm_plane_set_property(plane, pstate, property, val, blob_data);
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_set_property);
+
+void drm_atomic_helper_init_plane_state(struct drm_plane *plane,
+ struct drm_plane_state *pstate, void *state)
+{
+ /* snapshot current state: */
+ *pstate = *plane->state;
+ pstate->state = state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_init_plane_state);
+
+void drm_atomic_helper_destroy_plane_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_destroy_plane_state);
+
+static struct drm_plane_state *
+drm_atomic_helper_get_plane_state(struct drm_plane *plane, void *state)
+{
+ struct drm_atomic_helper_state *a = state;
+ struct drm_plane_state *pstate;
+ int ret;
+
+ /* grab lock of current crtc.. if crtc is NULL then grab all: */
+ if (plane->state->crtc)
+ ret = drm_modeset_lock(&plane->state->crtc->mutex, state);
+ else
+ ret = drm_modeset_lock_all_crtcs(plane->dev, state);
+ if (ret)
+ return ERR_PTR(ret);
+
+ pstate = a->pstates[plane->id];
+
+ if (!pstate) {
+ pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
+ if (!pstate)
+ return ERR_PTR(-ENOMEM);
+ drm_atomic_helper_init_plane_state(plane, pstate, state);
+ a->planes[plane->id] = plane;
+ a->pstates[plane->id] = pstate;
+ }
+
+ return pstate;
+}
+
+static void
+swap_plane_state(struct drm_plane *plane, struct drm_atomic_helper_state *a)
+{
+ struct drm_plane_state *pstate = a->pstates[plane->id];
+
+ /* clear transient state (only valid during atomic update): */
+ pstate->new_fb = false;
+
+ swap(plane->state, a->pstates[plane->id]);
+ plane->base.propvals = &plane->state->propvals;
+}
+
+static int
+drm_atomic_helper_commit_plane_state(struct drm_plane *plane,
+ struct drm_plane_state *pstate)
+{
+ struct drm_framebuffer *old_fb = NULL, *fb = NULL;
+ int ret = 0;
+
+ fb = pstate->fb;
+
+ if (pstate->crtc && fb) {
+ ret = plane->funcs->update_plane(plane, pstate->crtc, pstate->fb,
+ pstate->crtc_x, pstate->crtc_y, pstate->crtc_w, pstate->crtc_h,
+ pstate->src_x, pstate->src_y, pstate->src_w, pstate->src_h);
+ if (!ret) {
+ /* on success, update state and fb refcnting: */
+ /* NOTE: if we ensure no driver sets plane->state->fb = NULL
+ * on disable, we can move this up a level and not duplicate
+ * nearly the same thing for both update_plane and disable_plane
+ * cases.. I leave it like this for now to be paranoid due to
+ * the slightly different ordering in the two cases in the
+ * original code.
+ */
+ old_fb = plane->state->fb;
+ swap_plane_state(plane, pstate->state);
+ fb = NULL;
+ }
+ } else {
+ old_fb = plane->state->fb;
+ plane->funcs->disable_plane(plane);
+ swap_plane_state(plane, pstate->state);
+ }
+
+
+ if (fb)
+ drm_framebuffer_unreference(fb);
+ if (old_fb)
+ drm_framebuffer_unreference(old_fb);
+
+ return ret;
+}
const struct drm_atomic_helper_funcs drm_atomic_helper_funcs = {
+ .get_plane_state = drm_atomic_helper_get_plane_state,
+ .check_plane_state = drm_plane_check_state,
+ .commit_plane_state = drm_atomic_helper_commit_plane_state,
};
EXPORT_SYMBOL(drm_atomic_helper_funcs);
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 8180499..bb1a4fe 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -680,7 +680,20 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
* in this manner.
*/
if (atomic_read(&fb->refcount.refcount) > 1) {
+ void *state;
+
+ state = dev->driver->atomic_begin(dev, 0);
+ if (IS_ERR(state)) {
+ DRM_ERROR("failed to disable crtc and/or plane when fb was deleted\n");
+ return;
+ }
+
+ /* TODO once CRTC is converted to state/properties, we can push the
+ * locking down into drm_atomic_helper_commit(), since that is where
+ * the actual changes take place..
+ */
drm_modeset_lock_all(dev);
+
/* remove from any CRTC */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (crtc->fb == fb) {
@@ -695,9 +708,18 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
}
list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
- if (plane->fb == fb)
- drm_plane_force_disable(plane);
+ if (plane->state->fb == fb)
+ drm_plane_force_disable(plane, state);
}
+
+ /* just disabling stuff shouldn't fail, hopefully: */
+ if(dev->driver->atomic_check(dev, state))
+ DRM_ERROR("failed to disable crtc and/or plane when fb was deleted\n");
+ else
+ dev->driver->atomic_commit(dev, state);
+
+ dev->driver->atomic_end(dev, state);
+
drm_modeset_unlock_all(dev);
}
@@ -993,8 +1015,12 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
const uint32_t *formats, uint32_t format_count,
bool priv)
{
+ struct drm_mode_config *config = &dev->mode_config;
int ret;
+ if (!plane->state)
+ plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
+
drm_modeset_lock_all(dev);
ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
@@ -1002,7 +1028,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
goto out;
plane->base.properties = &plane->properties;
- plane->base.propvals = &plane->propvals;
+ plane->base.propvals = &plane->state->propvals;
plane->dev = dev;
plane->funcs = funcs;
plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
@@ -1024,11 +1050,23 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
*/
if (!priv) {
list_add_tail(&plane->head, &dev->mode_config.plane_list);
+ plane->id = dev->mode_config.num_plane;
dev->mode_config.num_plane++;
} else {
INIT_LIST_HEAD(&plane->head);
}
+ drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
+ drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
+ drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
+ drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
+ drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
+ drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
+ drm_object_attach_property(&plane->base, config->prop_src_x, 0);
+ drm_object_attach_property(&plane->base, config->prop_src_y, 0);
+ drm_object_attach_property(&plane->base, config->prop_src_w, 0);
+ drm_object_attach_property(&plane->base, config->prop_src_h, 0);
+
out:
drm_modeset_unlock_all(dev);
@@ -1060,6 +1098,121 @@ void drm_plane_cleanup(struct drm_plane *plane)
}
EXPORT_SYMBOL(drm_plane_cleanup);
+int drm_plane_check_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ unsigned int fb_width, fb_height;
+ struct drm_framebuffer *fb = state->fb;
+ int i;
+
+ /* disabling the plane is allowed: */
+ if (!fb)
+ return 0;
+
+ fb_width = fb->width << 16;
+ fb_height = fb->height << 16;
+
+ /* Check whether this plane supports the fb pixel format. */
+ for (i = 0; i < plane->format_count; i++)
+ if (fb->pixel_format == plane->format_types[i])
+ break;
+ if (i == plane->format_count) {
+ DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format);
+ return -EINVAL;
+ }
+
+ /* Make sure source coordinates are inside the fb. */
+ if (state->src_w > fb_width ||
+ state->src_x > fb_width - state->src_w ||
+ state->src_h > fb_height ||
+ state->src_y > fb_height - state->src_h) {
+ DRM_DEBUG_KMS("Invalid source coordinates "
+ "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
+ state->src_w >> 16,
+ ((state->src_w & 0xffff) * 15625) >> 10,
+ state->src_h >> 16,
+ ((state->src_h & 0xffff) * 15625) >> 10,
+ state->src_x >> 16,
+ ((state->src_x & 0xffff) * 15625) >> 10,
+ state->src_y >> 16,
+ ((state->src_y & 0xffff) * 15625) >> 10);
+ return -ENOSPC;
+ }
+
+ /* Give drivers some help against integer overflows */
+ if (state->crtc_w > INT_MAX ||
+ state->crtc_x > INT_MAX - (int32_t) state->crtc_w ||
+ state->crtc_h > INT_MAX ||
+ state->crtc_y > INT_MAX - (int32_t) state->crtc_h) {
+ DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
+ state->crtc_w, state->crtc_h,
+ state->crtc_x, state->crtc_y);
+ return -ERANGE;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_plane_check_state);
+
+void drm_plane_commit_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ plane->state = state;
+ plane->base.propvals = &state->propvals;
+}
+EXPORT_SYMBOL(drm_plane_commit_state);
+
+int drm_plane_set_property(struct drm_plane *plane,
+ struct drm_plane_state *state,
+ struct drm_property *property,
+ uint64_t value, void *blob_data)
+{
+ struct drm_device *dev = plane->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+
+ drm_object_property_set_value(&plane->base,
+ &state->propvals, property, value, blob_data);
+
+ if (property == config->prop_fb_id) {
+ state->new_fb = true;
+ state->fb = drm_framebuffer_lookup(dev, value);
+ } else if (property == config->prop_crtc_id) {
+ struct drm_mode_object *obj = drm_property_get_obj(property, value);
+ struct drm_crtc *crtc = obj ? obj_to_crtc(obj) : NULL;
+ /* take the lock of the incoming crtc as well, moving
+ * plane between crtcs is synchronized on both incoming
+ * and outgoing crtc.
+ */
+ if (crtc) {
+ int ret = drm_modeset_lock(&crtc->mutex, state->state);
+ if (ret)
+ return ret;
+ }
+ state->crtc = crtc;
+ } else if (property == config->prop_crtc_x) {
+ state->crtc_x = U642I64(value);
+ } else if (property == config->prop_crtc_y) {
+ state->crtc_y = U642I64(value);
+ } else if (property == config->prop_crtc_w) {
+ state->crtc_w = value;
+ } else if (property == config->prop_crtc_h) {
+ state->crtc_h = value;
+ } else if (property == config->prop_src_x) {
+ state->src_x = value;
+ } else if (property == config->prop_src_y) {
+ state->src_y = value;
+ } else if (property == config->prop_src_w) {
+ state->src_w = value;
+ } else if (property == config->prop_src_h) {
+ state->src_h = value;
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_plane_set_property);
+
/**
* drm_plane_force_disable - Forcibly disable a plane
* @plane: plane to disable
@@ -1069,20 +1222,15 @@ EXPORT_SYMBOL(drm_plane_cleanup);
* Used when the plane's current framebuffer is destroyed,
* and when restoring fbdev mode.
*/
-void drm_plane_force_disable(struct drm_plane *plane)
+void drm_plane_force_disable(struct drm_plane *plane, void *state)
{
- int ret;
+ struct drm_mode_config *config = &plane->dev->mode_config;
- if (!plane->fb)
- return;
-
- ret = plane->funcs->disable_plane(plane);
- if (ret)
- DRM_ERROR("failed to disable plane with busy fb\n");
- /* disconnect the plane from the fb and crtc: */
- __drm_framebuffer_unreference(plane->fb);
- plane->fb = NULL;
- plane->crtc = NULL;
+ /* should turn off the crtc */
+ drm_mode_plane_set_obj_prop(plane, state,
+ config->prop_crtc_id, 0, NULL);
+ drm_mode_plane_set_obj_prop(plane, state,
+ config->prop_fb_id, 0, NULL);
}
EXPORT_SYMBOL(drm_plane_force_disable);
@@ -1132,21 +1280,78 @@ EXPORT_SYMBOL(drm_mode_destroy);
static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
{
- struct drm_property *edid;
- struct drm_property *dpms;
+ struct drm_property *prop;
/*
* Standard properties (apply to all connectors)
*/
- edid = drm_property_create(dev, DRM_MODE_PROP_BLOB |
+ prop = drm_property_create(dev, DRM_MODE_PROP_BLOB |
DRM_MODE_PROP_IMMUTABLE,
"EDID", 0);
- dev->mode_config.edid_property = edid;
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.edid_property = prop;
- dpms = drm_property_create_enum(dev, 0,
+ prop = drm_property_create_enum(dev, 0,
"DPMS", drm_dpms_enum_list,
ARRAY_SIZE(drm_dpms_enum_list));
- dev->mode_config.dpms_property = dpms;
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.dpms_property = prop;
+
+
+ prop = drm_property_create_range(dev, 0, "SRC_X", 0, UINT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_src_x = prop;
+
+ prop = drm_property_create_range(dev, 0, "SRC_Y", 0, UINT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_src_y = prop;
+
+ prop = drm_property_create_range(dev, 0, "SRC_W", 0, UINT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_src_w = prop;
+
+ prop = drm_property_create_range(dev, 0, "SRC_H", 0, UINT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_src_h = prop;
+
+ prop = drm_property_create_signed_range(dev, 0, "CRTC_X",
+ INT_MIN, INT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_crtc_x = prop;
+
+ prop = drm_property_create_signed_range(dev, 0, "CRTC_Y",
+ INT_MIN, INT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_crtc_y = prop;
+
+ prop = drm_property_create_range(dev, 0, "CRTC_W", 0, INT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_crtc_w = prop;
+
+ prop = drm_property_create_range(dev, 0, "CRTC_H", 0, INT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_crtc_h = prop;
+
+ prop = drm_property_create_object(dev, 0, "FB_ID", DRM_MODE_OBJECT_FB);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_fb_id = prop;
+
+ prop = drm_property_create_object(dev, 0,
+ "CRTC_ID", DRM_MODE_OBJECT_CRTC);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_crtc_id = prop;
return 0;
}
@@ -1939,13 +2144,13 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
goto out;
}
- if (plane->crtc)
- plane_resp->crtc_id = plane->crtc->base.id;
+ if (plane->state->crtc)
+ plane_resp->crtc_id = plane->state->crtc->base.id;
else
plane_resp->crtc_id = 0;
- if (plane->fb)
- plane_resp->fb_id = plane->fb->base.id;
+ if (plane->state->fb)
+ plane_resp->fb_id = plane->state->fb->base.id;
else
plane_resp->fb_id = 0;
@@ -1987,20 +2192,19 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_mode_set_plane *plane_req = data;
+ struct drm_mode_config *config = &dev->mode_config;
struct drm_plane *plane;
- struct drm_crtc *crtc;
- struct drm_framebuffer *fb = NULL, *old_fb = NULL;
+ void *state;
int ret = 0;
- unsigned int fb_width, fb_height;
- int i;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
- /*
- * First, find the plane, crtc, and fb objects. If not available,
- * we don't bother to call the driver.
- */
+retry:
+ state = dev->driver->atomic_begin(dev, 0);
+ if (IS_ERR(state))
+ return PTR_ERR(state);
+
plane = drm_plane_find(dev, plane_req->plane_id);
if (!plane) {
DRM_DEBUG_KMS("Unknown plane ID %d\n",
@@ -2008,98 +2212,37 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
return -ENOENT;
}
- /* No fb means shut it down */
- if (!plane_req->fb_id) {
- drm_modeset_lock_all(dev);
- old_fb = plane->fb;
- plane->funcs->disable_plane(plane);
- plane->crtc = NULL;
- plane->fb = NULL;
- drm_modeset_unlock_all(dev);
- goto out;
- }
-
- crtc = drm_crtc_find(dev, plane_req->crtc_id);
- if (!crtc) {
- DRM_DEBUG_KMS("Unknown crtc ID %d\n",
- plane_req->crtc_id);
- ret = -ENOENT;
- goto out;
- }
-
- fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
- if (!fb) {
- DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
- plane_req->fb_id);
- ret = -ENOENT;
- goto out;
- }
-
- /* Check whether this plane supports the fb pixel format. */
- for (i = 0; i < plane->format_count; i++)
- if (fb->pixel_format == plane->format_types[i])
- break;
- if (i == plane->format_count) {
- DRM_DEBUG_KMS("Invalid pixel format %s\n",
- drm_get_format_name(fb->pixel_format));
- ret = -EINVAL;
- goto out;
- }
-
- fb_width = fb->width << 16;
- fb_height = fb->height << 16;
-
- /* Make sure source coordinates are inside the fb. */
- if (plane_req->src_w > fb_width ||
- plane_req->src_x > fb_width - plane_req->src_w ||
- plane_req->src_h > fb_height ||
- plane_req->src_y > fb_height - plane_req->src_h) {
- DRM_DEBUG_KMS("Invalid source coordinates "
- "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
- plane_req->src_w >> 16,
- ((plane_req->src_w & 0xffff) * 15625) >> 10,
- plane_req->src_h >> 16,
- ((plane_req->src_h & 0xffff) * 15625) >> 10,
- plane_req->src_x >> 16,
- ((plane_req->src_x & 0xffff) * 15625) >> 10,
- plane_req->src_y >> 16,
- ((plane_req->src_y & 0xffff) * 15625) >> 10);
- ret = -ENOSPC;
- goto out;
- }
-
- /* Give drivers some help against integer overflows */
- if (plane_req->crtc_w > INT_MAX ||
- plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
- plane_req->crtc_h > INT_MAX ||
- plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
- DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
- plane_req->crtc_w, plane_req->crtc_h,
- plane_req->crtc_x, plane_req->crtc_y);
- ret = -ERANGE;
+ ret =
+ drm_mode_plane_set_obj_prop(plane, state,
+ config->prop_crtc_id, plane_req->crtc_id, NULL) ||
+ drm_mode_plane_set_obj_prop(plane, state,
+ config->prop_fb_id, plane_req->fb_id, NULL) ||
+ drm_mode_plane_set_obj_prop(plane, state,
+ config->prop_crtc_x, I642U64(plane_req->crtc_x), NULL) ||
+ drm_mode_plane_set_obj_prop(plane, state,
+ config->prop_crtc_y, I642U64(plane_req->crtc_y), NULL) ||
+ drm_mode_plane_set_obj_prop(plane, state,
+ config->prop_crtc_w, plane_req->crtc_w, NULL) ||
+ drm_mode_plane_set_obj_prop(plane, state,
+ config->prop_crtc_h, plane_req->crtc_h, NULL) ||
+ drm_mode_plane_set_obj_prop(plane, state,
+ config->prop_src_w, plane_req->src_w, NULL) ||
+ drm_mode_plane_set_obj_prop(plane, state,
+ config->prop_src_h, plane_req->src_h, NULL) ||
+ drm_mode_plane_set_obj_prop(plane, state,
+ config->prop_src_x, plane_req->src_x, NULL) ||
+ drm_mode_plane_set_obj_prop(plane, state,
+ config->prop_src_y, plane_req->src_y, NULL) ||
+ dev->driver->atomic_check(dev, state);
+ if (ret)
goto out;
- }
- drm_modeset_lock_all(dev);
- ret = plane->funcs->update_plane(plane, crtc, fb,
- plane_req->crtc_x, plane_req->crtc_y,
- plane_req->crtc_w, plane_req->crtc_h,
- plane_req->src_x, plane_req->src_y,
- plane_req->src_w, plane_req->src_h);
- if (!ret) {
- old_fb = plane->fb;
- plane->crtc = crtc;
- plane->fb = fb;
- fb = NULL;
- }
- drm_modeset_unlock_all(dev);
+ ret = dev->driver->atomic_commit(dev, state);
out:
- if (fb)
- drm_framebuffer_unreference(fb);
- if (old_fb)
- drm_framebuffer_unreference(old_fb);
-
+ dev->driver->atomic_end(dev, state);
+ if (ret == -EDEADLK)
+ goto retry;
return ret;
}
@@ -3427,7 +3570,7 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
}
-static int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
+int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
void *state, struct drm_property *property,
uint64_t value, void *blob_data)
{
@@ -3450,8 +3593,9 @@ static int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
return ret;
}
+EXPORT_SYMBOL(drm_mode_connector_set_obj_prop);
-static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
+int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
void *state, struct drm_property *property,
uint64_t value, void *blob_data)
{
@@ -3466,8 +3610,9 @@ static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
return ret;
}
+EXPORT_SYMBOL(drm_mode_crtc_set_obj_prop);
-static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
void *state, struct drm_property *property,
uint64_t value, void *blob_data)
{
@@ -3476,12 +3621,10 @@ static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
if (plane->funcs->set_property)
ret = plane->funcs->set_property(plane, state, property,
value, blob_data);
- if (!ret)
- drm_object_property_set_value(&plane->base, &plane->propvals,
- property, value, NULL);
return ret;
}
+EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
static int drm_mode_set_obj_prop(struct drm_mode_object *obj,
void *state, struct drm_property *property,
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 1b6b6f4..5773468 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -286,12 +286,27 @@ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
struct drm_device *dev = fb_helper->dev;
struct drm_plane *plane;
bool error = false;
+ void *state;
int i;
drm_warn_on_modeset_not_all_locked(dev);
+ state = dev->driver->atomic_begin(dev, 0);
+ if (IS_ERR(state)) {
+ DRM_ERROR("failed to restore fbdev mode\n");
+ return true;
+ }
+
list_for_each_entry(plane, &dev->mode_config.plane_list, head)
- drm_plane_force_disable(plane);
+ drm_plane_force_disable(plane, state);
+
+ /* just disabling stuff shouldn't fail, hopefully: */
+ if(dev->driver->atomic_check(dev, state))
+ DRM_ERROR("failed to restore fbdev mode\n");
+ else
+ dev->driver->atomic_commit(dev, state);
+
+ dev->driver->atomic_end(dev, state);
for (i = 0; i < fb_helper->crtc_count; i++) {
struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 82a9fca..4ae55b8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -124,8 +124,8 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
if (ret)
return ret;
- plane->crtc = crtc;
- plane->fb = crtc->fb;
+ plane->state->crtc = crtc;
+ plane->state->fb = crtc->fb;
exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 06f1b2a..dbe2e19 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -127,7 +127,7 @@ static void disable_plane_to_crtc(struct drm_device *dev,
* (encoder->crtc)
*/
list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
- if (plane->crtc == old_crtc) {
+ if (plane->state->crtc == old_crtc) {
/*
* do not change below call order.
*
@@ -138,7 +138,7 @@ static void disable_plane_to_crtc(struct drm_device *dev,
* have new_crtc because new_crtc was set to
* encoder->crtc in advance.
*/
- plane->crtc = new_crtc;
+ plane->state->crtc = new_crtc;
plane->funcs->disable_plane(plane);
}
}
@@ -247,7 +247,7 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
/* all planes connected to this encoder should be also disabled. */
list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
- if (plane->crtc == encoder->crtc)
+ if (plane->state->crtc == encoder->crtc)
plane->funcs->disable_plane(plane);
}
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index 2e31fb8..d585a4c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -10,6 +10,7 @@
*/
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
@@ -149,7 +150,7 @@ void exynos_plane_commit(struct drm_plane *plane)
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
- exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
+ exynos_drm_fn_encoder(plane->state->crtc, &overlay->zpos,
exynos_drm_encoder_plane_commit);
}
@@ -162,7 +163,7 @@ void exynos_plane_dpms(struct drm_plane *plane, int mode)
if (exynos_plane->enabled)
return;
- exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
+ exynos_drm_fn_encoder(plane->state->crtc, &overlay->zpos,
exynos_drm_encoder_plane_enable);
exynos_plane->enabled = true;
@@ -170,7 +171,7 @@ void exynos_plane_dpms(struct drm_plane *plane, int mode)
if (!exynos_plane->enabled)
return;
- exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
+ exynos_drm_fn_encoder(plane->state->crtc, &overlay->zpos,
exynos_drm_encoder_plane_disable);
exynos_plane->enabled = false;
@@ -192,7 +193,7 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
if (ret < 0)
return ret;
- plane->crtc = crtc;
+ plane->state->crtc = crtc;
exynos_plane_commit(plane);
exynos_plane_dpms(plane, DRM_MODE_DPMS_ON);
@@ -225,13 +226,17 @@ static int exynos_plane_set_property(struct drm_plane *plane,
struct drm_device *dev = plane->dev;
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
struct exynos_drm_private *dev_priv = dev->dev_private;
+ struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+ if (IS_ERR(pstate))
+ return PTR_ERR(pstate);
if (property == dev_priv->plane_zpos_property) {
exynos_plane->overlay.zpos = val;
return 0;
}
- return -EINVAL;
+ return drm_plane_set_property(plane, pstate, property, val, blob_data);
}
static struct drm_plane_funcs exynos_plane_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index b9fabf8..0d1d34a 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -897,20 +897,21 @@ static int
intel_disable_plane(struct drm_plane *plane)
{
struct drm_device *dev = plane->dev;
+ struct drm_plane_state *state = plane->state;
struct intel_plane *intel_plane = to_intel_plane(plane);
struct intel_crtc *intel_crtc;
- if (!plane->fb)
+ if (!state->fb)
return 0;
- if (WARN_ON(!plane->crtc))
+ if (WARN_ON(!state->crtc))
return -EINVAL;
- intel_crtc = to_intel_crtc(plane->crtc);
+ intel_crtc = to_intel_crtc(state->crtc);
if (intel_crtc->active) {
- intel_enable_primary(plane->crtc);
- intel_plane->disable_plane(plane, plane->crtc);
+ intel_enable_primary(state->crtc);
+ intel_plane->disable_plane(plane, state->crtc);
}
if (intel_plane->obj) {
@@ -1000,11 +1001,12 @@ out_unlock:
void intel_plane_restore(struct drm_plane *plane)
{
struct intel_plane *intel_plane = to_intel_plane(plane);
+ struct drm_plane_state *state = plane->state;
- if (!plane->crtc || !plane->fb)
+ if (!state->crtc || !state->fb)
return;
- intel_update_plane(plane, plane->crtc, plane->fb,
+ intel_update_plane(plane, state->crtc, state->fb,
intel_plane->crtc_x, intel_plane->crtc_y,
intel_plane->crtc_w, intel_plane->crtc_h,
intel_plane->src_x, intel_plane->src_y,
@@ -1013,7 +1015,9 @@ void intel_plane_restore(struct drm_plane *plane)
void intel_plane_disable(struct drm_plane *plane)
{
- if (!plane->crtc || !plane->fb)
+ struct drm_plane_state *state = plane->state;
+
+ if (!state->crtc || !state->fb)
return;
intel_disable_plane(plane);
@@ -1023,6 +1027,7 @@ static const struct drm_plane_funcs intel_plane_funcs = {
.update_plane = intel_update_plane,
.disable_plane = intel_disable_plane,
.destroy = intel_destroy_plane,
+ .set_property = drm_atomic_helper_plane_set_property,
};
static uint32_t ilk_plane_formats[] = {
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
index 80af12a..37a3fd2 100644
--- a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
@@ -263,7 +263,7 @@ static void blend_setup(struct drm_crtc *crtc)
int idx = idxs[pipe_id];
if (idx > 0) {
const struct mdp4_format *format =
- to_mdp4_format(msm_framebuffer_format(plane->fb));
+ to_mdp4_format(msm_framebuffer_format(plane->state->fb));
alpha[idx-1] = format->alpha_enable;
}
mixer_cfg |= mixercfg(mdp4_crtc->mixer, pipe_id, stages[idx]);
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp4/mdp4_plane.c
index 880e96d..037ac83 100644
--- a/drivers/gpu/drm/msm/mdp4/mdp4_plane.c
+++ b/drivers/gpu/drm/msm/mdp4/mdp4_plane.c
@@ -45,11 +45,14 @@ static int mdp4_plane_update(struct drm_plane *plane,
uint32_t src_w, uint32_t src_h)
{
struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
+ struct drm_plane_state *state = plane->state;
mdp4_plane->enabled = true;
- if (plane->fb)
- drm_framebuffer_unreference(plane->fb);
+ if (state->fb) {
+ drm_framebuffer_unreference(state->fb);
+ state->fb = NULL;
+ }
drm_framebuffer_reference(fb);
@@ -62,8 +65,8 @@ static int mdp4_plane_disable(struct drm_plane *plane)
{
struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
DBG("%s: disable", mdp4_plane->name);
- if (plane->crtc)
- mdp4_crtc_detach(plane->crtc, plane);
+ if (plane->state->crtc)
+ mdp4_crtc_detach(plane->state->crtc, plane);
return 0;
}
@@ -87,8 +90,10 @@ void mdp4_plane_install_properties(struct drm_plane *plane,
int mdp4_plane_set_property(struct drm_plane *plane, void *state,
struct drm_property *property, uint64_t val, void *blob_data)
{
- // XXX
- return -EINVAL;
+ struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+ if (IS_ERR(pstate))
+ return PTR_ERR(pstate);
+ return drm_plane_set_property(plane, pstate, property, val, blob_data);
}
static const struct drm_plane_funcs mdp4_plane_funcs = {
@@ -117,7 +122,7 @@ void mdp4_plane_set_scanout(struct drm_plane *plane,
msm_gem_get_iova(msm_framebuffer_bo(fb, 0), mdp4_kms->id, &iova);
mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP0_BASE(pipe), iova);
- plane->fb = fb;
+ plane->state->fb = fb;
}
#define MDP4_VG_PHASE_STEP_DEFAULT 0x20000000
diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c
index fc938f7..a6a4375 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c
@@ -24,6 +24,7 @@
*/
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fourcc.h>
@@ -213,6 +214,10 @@ nv10_set_property(struct drm_plane *plane, void *state,
uint64_t value, void *blob_data)
{
struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
+ struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+ if (IS_ERR(pstate))
+ return PTR_ERR(pstate);
if (property == nv_plane->props.colorkey)
nv_plane->colorkey = value;
@@ -227,7 +232,8 @@ nv10_set_property(struct drm_plane *plane, void *state,
else if (property == nv_plane->props.iturbt_709)
nv_plane->iturbt_709 = value;
else
- return -EINVAL;
+ return drm_plane_set_property(plane, pstate,
+ property, value, blob_data);
nv10_set_params(nv_plane);
return 0;
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index 357342d..524a81a 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -210,7 +210,7 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
/* and any attached overlay planes: */
for (i = 0; i < priv->num_planes; i++) {
struct drm_plane *plane = priv->planes[i];
- if (plane->crtc == crtc)
+ if (plane->state->crtc == crtc)
WARN_ON(omap_plane_dpms(plane, mode));
}
}
@@ -651,7 +651,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
omap_crtc->channel = channel;
omap_crtc->plane = plane;
- omap_crtc->plane->crtc = crtc;
+ omap_crtc->plane->state->crtc = crtc;
omap_crtc->name = channel_names[channel];
omap_crtc->pipe = id;
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 1b09696..e1e794a 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -559,7 +559,7 @@ static void dev_lastclose(struct drm_device *dev)
for (i = 0; i < priv->num_planes; i++) {
drm_object_property_set_value(&priv->planes[i]->base,
- &priv->planes[i]->propvals,
+ &priv->planes[i]->state->propvals,
priv->rotation_prop, 0, NULL);
}
}
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index fe32f1b..b85bd61 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -116,9 +116,10 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
container_of(apply, struct omap_plane, apply);
struct omap_drm_window *win = &omap_plane->win;
struct drm_plane *plane = &omap_plane->base;
+ struct drm_plane_state *state = plane->state;
struct drm_device *dev = plane->dev;
struct omap_overlay_info *info = &omap_plane->info;
- struct drm_crtc *crtc = plane->crtc;
+ struct drm_crtc *crtc = state->crtc;
enum omap_channel channel;
bool enabled = omap_plane->enabled && crtc;
bool ilace, replication;
@@ -127,7 +128,7 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
DBG("%s, enabled=%d", omap_plane->name, enabled);
/* if fb has changed, pin new fb: */
- update_pin(plane, enabled ? plane->fb : NULL);
+ update_pin(plane, enabled ? state->fb : NULL);
if (!enabled) {
dispc_ovl_enable(omap_plane->id, false);
@@ -137,7 +138,7 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
channel = omap_crtc_channel(crtc);
/* update scanout: */
- omap_framebuffer_update_scanout(plane->fb, win, info);
+ omap_framebuffer_update_scanout(state->fb, win, info);
DBG("%dx%d -> %dx%d (%d)", info->width, info->height,
info->out_width, info->out_height,
@@ -179,16 +180,18 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply)
cb.fxn(cb.arg);
if (omap_plane->enabled) {
- omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
+ omap_framebuffer_flush(plane->state->fb,
+ info->pos_x, info->pos_y,
info->out_width, info->out_height);
}
}
static int apply(struct drm_plane *plane)
{
- if (plane->crtc) {
+ struct drm_plane_state *state = plane->state;
+ if (state->crtc) {
struct omap_plane *omap_plane = to_omap_plane(plane);
- return omap_crtc_apply(plane->crtc, &omap_plane->apply);
+ return omap_crtc_apply(state->crtc, &omap_plane->apply);
}
return 0;
}
@@ -203,6 +206,7 @@ int omap_plane_mode_set(struct drm_plane *plane,
{
struct omap_plane *omap_plane = to_omap_plane(plane);
struct omap_drm_window *win = &omap_plane->win;
+ struct drm_plane_state *state = plane->state;
win->crtc_x = crtc_x;
win->crtc_y = crtc_y;
@@ -225,8 +229,8 @@ int omap_plane_mode_set(struct drm_plane *plane,
omap_plane->apply_done_cb.arg = arg;
}
- plane->fb = fb;
- plane->crtc = crtc;
+ state->fb = fb;
+ state->crtc = crtc;
return apply(plane);
}
@@ -239,10 +243,12 @@ static int omap_plane_update(struct drm_plane *plane,
uint32_t src_w, uint32_t src_h)
{
struct omap_plane *omap_plane = to_omap_plane(plane);
+ struct drm_plane_state *state = plane->state;
+
omap_plane->enabled = true;
- if (plane->fb)
- drm_framebuffer_unreference(plane->fb);
+ if (state->fb)
+ drm_framebuffer_unreference(state->fb);
drm_framebuffer_reference(fb);
@@ -332,8 +338,12 @@ int omap_plane_set_property(struct drm_plane *plane, void *state,
{
struct omap_plane *omap_plane = to_omap_plane(plane);
struct omap_drm_private *priv = plane->dev->dev_private;
+ struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
int ret = -EINVAL;
+ if (IS_ERR(pstate))
+ return PTR_ERR(pstate);
+
if (property == priv->rotation_prop) {
DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val);
omap_plane->win.rotation = val;
@@ -342,6 +352,9 @@ int omap_plane_set_property(struct drm_plane *plane, void *state,
DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val);
omap_plane->info.zorder = val;
ret = apply(plane);
+ } else {
+ ret = drm_plane_set_property(plane, pstate, property,
+ val, blob_data);
}
return ret;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index 5691743..4121a58 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -14,6 +14,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
@@ -403,6 +404,10 @@ static int rcar_du_plane_set_property(struct drm_plane *plane,
{
struct rcar_du_plane *rplane = to_rcar_plane(plane);
struct rcar_du_group *rgrp = rplane->group;
+ struct drm_plane_state *pstate = drm_atomic_get_plane_state(plane, state);
+
+ if (IS_ERR(pstate))
+ return PTR_ERR(pstate);
if (property == rgrp->planes.alpha)
rcar_du_plane_set_alpha(rplane, value);
@@ -411,7 +416,8 @@ static int rcar_du_plane_set_property(struct drm_plane *plane,
else if (property == rgrp->planes.zpos)
rcar_du_plane_set_zpos(rplane, value);
else
- return -EINVAL;
+ return drm_plane_set_property(plane, pstate,
+ property, value, blob_data);
return 0;
}
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
index b72ba99..9e86b99 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
@@ -238,7 +238,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc)
/* Setup planes. */
list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
- if (plane->crtc == crtc)
+ if (plane->state->crtc == crtc)
shmob_drm_plane_setup(plane);
}
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
index 060ae03..22da5c1 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
@@ -14,6 +14,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
@@ -166,10 +167,10 @@ void shmob_drm_plane_setup(struct drm_plane *plane)
{
struct shmob_drm_plane *splane = to_shmob_plane(plane);
- if (plane->fb == NULL)
+ if (plane->state->fb == NULL)
return;
- __shmob_drm_plane_setup(splane, plane->fb);
+ __shmob_drm_plane_setup(splane, plane->state->fb);
}
static int
@@ -228,6 +229,7 @@ static void shmob_drm_plane_destroy(struct drm_plane *plane)
static const struct drm_plane_funcs shmob_drm_plane_funcs = {
.update_plane = shmob_drm_plane_update,
.disable_plane = shmob_drm_plane_disable,
+ .set_property = drm_atomic_helper_plane_set_property,
.destroy = shmob_drm_plane_destroy,
};
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index ae1cb31..1794c6e 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -73,11 +73,12 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
static int tegra_plane_disable(struct drm_plane *plane)
{
- struct tegra_dc *dc = to_tegra_dc(plane->crtc);
+ struct drm_plane_state *state = plane->state;
+ struct tegra_dc *dc = to_tegra_dc(state->crtc);
struct tegra_plane *p = to_tegra_plane(plane);
unsigned long value;
- if (!plane->crtc)
+ if (!state->crtc)
return 0;
value = WINDOW_A_SELECT << p->index;
@@ -309,13 +310,14 @@ static void tegra_crtc_disable(struct drm_crtc *crtc)
struct drm_plane *plane;
list_for_each_entry(plane, &drm->mode_config.plane_list, head) {
- if (plane->crtc == crtc) {
+ struct drm_plane_state *state = plane->state;
+ if (state->crtc == crtc) {
tegra_plane_disable(plane);
- plane->crtc = NULL;
+ state->crtc = NULL;
- if (plane->fb) {
- drm_framebuffer_unreference(plane->fb);
- plane->fb = NULL;
+ if (state->fb) {
+ drm_framebuffer_unreference(state->fb);
+ state->fb = NULL;
}
}
}
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index d77f00e..4ca8360 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -62,7 +62,9 @@
* struct drm_atomic_helper_funcs - helper funcs used by the atomic helpers
*/
struct drm_atomic_helper_funcs {
- int dummy; /* for now */
+ struct drm_plane_state *(*get_plane_state)(struct drm_plane *plane, void *state);
+ int (*check_plane_state)(struct drm_plane *plane, struct drm_plane_state *pstate);
+ int (*commit_plane_state)(struct drm_plane *plane, struct drm_plane_state *pstate);
};
const extern struct drm_atomic_helper_funcs drm_atomic_helper_funcs;
@@ -76,6 +78,39 @@ int drm_atomic_helper_commit(struct drm_device *dev, void *state);
int drm_atomic_helper_commit_unlocked(struct drm_device *dev, void *state);
void drm_atomic_helper_end(struct drm_device *dev, void *state);
+int drm_atomic_helper_plane_set_property(struct drm_plane *plane, void *state,
+ struct drm_property *property, uint64_t val, void *blob_data);
+void drm_atomic_helper_init_plane_state(struct drm_plane *plane,
+ struct drm_plane_state *pstate, void *state);
+void drm_atomic_helper_destroy_plane_state(struct drm_plane *plane,
+ struct drm_plane_state *state);
+
+static inline struct drm_plane_state *
+drm_atomic_get_plane_state(struct drm_plane *plane, void *state)
+{
+ const struct drm_atomic_helper_funcs *funcs =
+ plane->dev->driver->atomic_helpers;
+ return funcs->get_plane_state(plane, state);
+}
+
+static inline int
+drm_atomic_check_plane_state(struct drm_plane *plane,
+ struct drm_plane_state *pstate)
+{
+ const struct drm_atomic_helper_funcs *funcs =
+ plane->dev->driver->atomic_helpers;
+ return funcs->check_plane_state(plane, pstate);
+}
+
+static inline int
+drm_atomic_commit_plane_state(struct drm_plane *plane,
+ struct drm_plane_state *pstate)
+{
+ const struct drm_atomic_helper_funcs *funcs =
+ plane->dev->driver->atomic_helpers;
+ return funcs->commit_plane_state(plane, pstate);
+}
+
/**
* struct drm_atomic_helper_state - the state object used by atomic helpers
*/
@@ -83,6 +118,8 @@ struct drm_atomic_helper_state {
struct kref refcount;
struct drm_device *dev;
uint32_t flags;
+ struct drm_plane **planes;
+ struct drm_plane_state **pstates;
bool committed;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 40eec19..9a4c16e 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -753,6 +753,45 @@ struct drm_plane_funcs {
};
/**
+ * drm_plane_state - mutable plane state
+ * @new_fb: has the fb been changed
+ * @crtc: currently bound CRTC
+ * @fb: currently bound fb
+ * @crtc_x: left position of visible portion of plane on crtc
+ * @crtc_y: upper position of visible portion of plane on crtc
+ * @crtc_w: width of visible portion of plane on crtc
+ * @crtc_h: height of visible portion of plane on crtc
+ * @src_x: left position of visible portion of plane within
+ * plane (in 16.16)
+ * @src_y: upper position of visible portion of plane within
+ * plane (in 16.16)
+ * @src_w: width of visible portion of plane (in 16.16)
+ * @src_h: height of visible portion of plane (in 16.16)
+ * @propvals: property values
+ * @state: current global/toplevel state object (for atomic) while an
+ * update is in progress, NULL otherwise.
+ */
+struct drm_plane_state {
+ bool new_fb : 1;
+ struct drm_crtc *crtc;
+ struct drm_framebuffer *fb;
+
+ /* Signed dest location allows it to be partially off screen */
+ int32_t crtc_x, crtc_y;
+ uint32_t crtc_w, crtc_h;
+
+ /* Source values are 16.16 fixed point */
+ uint32_t src_x, src_y;
+ uint32_t src_h, src_w;
+
+ bool enabled;
+
+ struct drm_object_property_values propvals;
+
+ void *state;
+};
+
+/**
* drm_plane - central DRM plane control structure
* @dev: DRM device this plane belongs to
* @head: for list management
@@ -760,8 +799,8 @@ struct drm_plane_funcs {
* @possible_crtcs: pipes this plane can be bound to
* @format_types: array of formats supported by this plane
* @format_count: number of formats supported
- * @crtc: currently bound CRTC
- * @fb: currently bound fb
+ * @id: plane number, 0..n
+ * @state: the mutable state
* @funcs: helper functions
* @properties: property tracking for this plane
*/
@@ -775,13 +814,17 @@ struct drm_plane {
uint32_t *format_types;
uint32_t format_count;
- struct drm_crtc *crtc;
- struct drm_framebuffer *fb;
+ int id;
+
+ /*
+ * State that can be updated from userspace, and atomically
+ * commited or rolled back:
+ */
+ struct drm_plane_state *state;
const struct drm_plane_funcs *funcs;
struct drm_object_properties properties;
- struct drm_object_property_values propvals;
};
/**
@@ -962,8 +1005,20 @@ struct drm_mode_config {
bool poll_running;
struct delayed_work output_poll_work;
- /* pointers to standard properties */
+ /* just so blob properties can always be in a list: */
struct list_head property_blob_list;
+
+ /* pointers to standard properties */
+ struct drm_property *prop_src_x;
+ struct drm_property *prop_src_y;
+ struct drm_property *prop_src_w;
+ struct drm_property *prop_src_h;
+ struct drm_property *prop_crtc_x;
+ struct drm_property *prop_crtc_y;
+ struct drm_property *prop_crtc_w;
+ struct drm_property *prop_crtc_h;
+ struct drm_property *prop_fb_id;
+ struct drm_property *prop_crtc_id;
struct drm_property *edid_property;
struct drm_property *dpms_property;
@@ -1043,7 +1098,15 @@ extern int drm_plane_init(struct drm_device *dev,
const uint32_t *formats, uint32_t format_count,
bool priv);
extern void drm_plane_cleanup(struct drm_plane *plane);
-extern void drm_plane_force_disable(struct drm_plane *plane);
+extern void drm_plane_force_disable(struct drm_plane *plane, void *state);
+extern int drm_plane_check_state(struct drm_plane *plane,
+ struct drm_plane_state *state);
+extern void drm_plane_commit_state(struct drm_plane *plane,
+ struct drm_plane_state *state);
+extern int drm_plane_set_property(struct drm_plane *plane,
+ struct drm_plane_state *state,
+ struct drm_property *property,
+ uint64_t value, void *blob_data);
extern void drm_encoder_cleanup(struct drm_encoder *encoder);
@@ -1115,6 +1178,17 @@ extern int drm_object_property_set_value(struct drm_mode_object *obj,
extern int drm_object_property_get_value(struct drm_mode_object *obj,
struct drm_property *property,
uint64_t *value);
+
+int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
+ void *state, struct drm_property *property,
+ uint64_t value, void *blob_data);
+int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
+ void *state, struct drm_property *property,
+ uint64_t value, void *blob_data);
+int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+ void *state, struct drm_property *property,
+ uint64_t value, void *blob_data);
+
extern int drm_framebuffer_init(struct drm_device *dev,
struct drm_framebuffer *fb,
const struct drm_framebuffer_funcs *funcs);
--
1.8.4.2
More information about the dri-devel
mailing list