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