@@ -410,7 +410,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
}
list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
- if (plane->fb == fb) {
+ if (plane->state->fb == fb) {
/* should turn off the crtc */
drm_mode_plane_set_obj_prop(plane, state, config->prop_crtc_id, 0);
drm_mode_plane_set_obj_prop(plane, state, config->prop_fb_id, 0);
@@ -688,7 +688,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,
@@ -749,6 +749,110 @@ 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)
+{
+ 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);
+
+ if (property == config->prop_fb_id) {
+ struct drm_mode_object *obj = drm_property_get_obj(property, value);
+ state->fb = obj ? obj_to_fb(obj) : NULL;
+ } else if (property == config->prop_crtc_id) {
+ struct drm_mode_object *obj = drm_property_get_obj(property, value);
+ state->crtc = obj ? obj_to_crtc(obj) : NULL;
+ } else if (property == config->prop_crtc_x) {
+ state->crtc_x = U642I64(value);
+ } else if (property == config->prop_crtc_y) {
+ state->crtc_y = U642I64(value);
+ } else if (property == config->prop_crtc_w) {
+ state->crtc_w = value;
+ } else if (property == config->prop_crtc_h) {
+ state->crtc_h = value;
+ } else if (property == config->prop_src_x) {
+ state->src_x = value;
+ } else if (property == config->prop_src_y) {
+ state->src_y = value;
+ } else if (property == config->prop_src_w) {
+ state->src_w = value;
+ } else if (property == config->prop_src_h) {
+ state->src_h = value;
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_plane_set_property);
+
/**
* drm_mode_create - create a new display mode
* @dev: DRM device
@@ -1794,13 +1898,13 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
}
plane = obj_to_plane(obj);
- if (plane->crtc)
- plane_resp->crtc_id = plane->crtc->base.id;
+ if (plane->state->crtc)
+ plane_resp->crtc_id = plane->state->crtc->base.id;
else
plane_resp->crtc_id = 0;
- if (plane->fb)
- plane_resp->fb_id = plane->fb->base.id;
+ if (plane->state->fb)
+ plane_resp->fb_id = plane->state->fb->base.id;
else
plane_resp->fb_id = 0;
@@ -3359,9 +3463,6 @@ 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);
- if (!ret)
- drm_object_property_set_value(&plane->base, &plane->propvals,
- property, value);
return ret;
}
@@ -641,6 +641,37 @@ struct drm_plane_funcs {
};
/**
+ * drm_plane_state - mutable plane state
+ * @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
+ */
+struct drm_plane_state {
+ 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;
+
+ struct drm_object_property_values propvals;
+};
+
+/**
* drm_plane - central DRM plane control structure
* @dev: DRM device this plane belongs to
* @head: for list management
@@ -648,11 +679,9 @@ 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
+ * @state: the mutable state
* @gamma_size: size of gamma table
* @gamma_store: gamma correction table
- * @enabled: enabled flag
* @funcs: helper functions
* @helper_private: storage for drver layer
* @properties: property tracking for this plane
@@ -667,20 +696,20 @@ struct drm_plane {
uint32_t *format_types;
uint32_t format_count;
- struct drm_crtc *crtc;
- struct drm_framebuffer *fb;
+ /*
+ * State that can be updated from userspace, and atomically
+ * commited or rolled back:
+ */
+ struct drm_plane_state *state;
/* CRTC gamma size for reporting to userspace */
uint32_t gamma_size;
uint16_t *gamma_store;
- bool enabled;
-
const struct drm_plane_funcs *funcs;
void *helper_private;
struct drm_object_properties properties;
- struct drm_object_property_values propvals;
};
/**
@@ -888,6 +917,13 @@ 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 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);
extern void drm_encoder_cleanup(struct drm_encoder *encoder);
From: Rob Clark <rob@ti.com> Break the mutable state of a plane out into a separate structure. 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_crtc.c | 119 ++++++++++++++++++++++++++++++++++++++++---- include/drm/drm_crtc.h | 52 ++++++++++++++++--- 2 files changed, 154 insertions(+), 17 deletions(-)