1 /* $NetBSD: drm_plane.c,v 1.4 2021/12/19 01:13:52 riastradh Exp $ */
2
3 /*
4 * Copyright (c) 2016 Intel Corporation
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that copyright
9 * notice and this permission notice appear in supporting documentation, and
10 * that the name of the copyright holders not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. The copyright holders make no representations
13 * about the suitability of this software for any purpose. It is provided "as
14 * is" without express or implied warranty.
15 *
16 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22 * OF THIS SOFTWARE.
23 */
24
25 #include <sys/cdefs.h>
26 __KERNEL_RCSID(0, "$NetBSD: drm_plane.c,v 1.4 2021/12/19 01:13:52 riastradh Exp $");
27
28 #include <linux/slab.h>
29 #include <linux/uaccess.h>
30
31 #include <drm/drm_plane.h>
32 #include <drm/drm_drv.h>
33 #include <drm/drm_print.h>
34 #include <drm/drm_framebuffer.h>
35 #include <drm/drm_file.h>
36 #include <drm/drm_crtc.h>
37 #include <drm/drm_fourcc.h>
38 #include <drm/drm_vblank.h>
39
40 #include "drm_crtc_internal.h"
41
42 /**
43 * DOC: overview
44 *
45 * A plane represents an image source that can be blended with or overlayed on
46 * top of a CRTC during the scanout process. Planes take their input data from a
47 * &drm_framebuffer object. The plane itself specifies the cropping and scaling
48 * of that image, and where it is placed on the visible are of a display
49 * pipeline, represented by &drm_crtc. A plane can also have additional
50 * properties that specify how the pixels are positioned and blended, like
51 * rotation or Z-position. All these properties are stored in &drm_plane_state.
52 *
53 * To create a plane, a KMS drivers allocates and zeroes an instances of
54 * &struct drm_plane (possibly as part of a larger structure) and registers it
55 * with a call to drm_universal_plane_init().
56 *
57 * Cursor and overlay planes are optional. All drivers should provide one
58 * primary plane per CRTC to avoid surprising userspace too much. See enum
59 * drm_plane_type for a more in-depth discussion of these special uapi-relevant
60 * plane types. Special planes are associated with their CRTC by calling
61 * drm_crtc_init_with_planes().
62 *
63 * The type of a plane is exposed in the immutable "type" enumeration property,
64 * which has one of the following values: "Overlay", "Primary", "Cursor".
65 */
66
drm_num_planes(struct drm_device * dev)67 static unsigned int drm_num_planes(struct drm_device *dev)
68 {
69 unsigned int num = 0;
70 struct drm_plane *tmp;
71
72 drm_for_each_plane(tmp, dev) {
73 num++;
74 }
75
76 return num;
77 }
78
79 static inline u32 *
formats_ptr(struct drm_format_modifier_blob * blob)80 formats_ptr(struct drm_format_modifier_blob *blob)
81 {
82 return (u32 *)(((char *)blob) + blob->formats_offset);
83 }
84
85 static inline struct drm_format_modifier *
modifiers_ptr(struct drm_format_modifier_blob * blob)86 modifiers_ptr(struct drm_format_modifier_blob *blob)
87 {
88 return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
89 }
90
create_in_format_blob(struct drm_device * dev,struct drm_plane * plane)91 static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane)
92 {
93 const struct drm_mode_config *config = &dev->mode_config;
94 struct drm_property_blob *blob;
95 struct drm_format_modifier *mod;
96 size_t blob_size, formats_size, modifiers_size;
97 struct drm_format_modifier_blob *blob_data;
98 unsigned int i, j;
99
100 formats_size = sizeof(__u32) * plane->format_count;
101 if (WARN_ON(!formats_size)) {
102 /* 0 formats are never expected */
103 return 0;
104 }
105
106 modifiers_size =
107 sizeof(struct drm_format_modifier) * plane->modifier_count;
108
109 blob_size = sizeof(struct drm_format_modifier_blob);
110 /* Modifiers offset is a pointer to a struct with a 64 bit field so it
111 * should be naturally aligned to 8B.
112 */
113 BUILD_BUG_ON(sizeof(struct drm_format_modifier_blob) % 8);
114 blob_size += round_up(formats_size, 8);
115 blob_size += modifiers_size;
116
117 blob = drm_property_create_blob(dev, blob_size, NULL);
118 if (IS_ERR(blob))
119 return -1;
120
121 blob_data = blob->data;
122 blob_data->version = FORMAT_BLOB_CURRENT;
123 blob_data->count_formats = plane->format_count;
124 blob_data->formats_offset = sizeof(struct drm_format_modifier_blob);
125 blob_data->count_modifiers = plane->modifier_count;
126
127 blob_data->modifiers_offset =
128 round_up(blob_data->formats_offset + formats_size, 8);
129
130 memcpy(formats_ptr(blob_data), plane->format_types, formats_size);
131
132 /* If we can't determine support, just bail */
133 if (!plane->funcs->format_mod_supported)
134 goto done;
135
136 mod = modifiers_ptr(blob_data);
137 for (i = 0; i < plane->modifier_count; i++) {
138 for (j = 0; j < plane->format_count; j++) {
139 if (plane->funcs->format_mod_supported(plane,
140 plane->format_types[j],
141 plane->modifiers[i])) {
142
143 mod->formats |= 1ULL << j;
144 }
145 }
146
147 mod->modifier = plane->modifiers[i];
148 mod->offset = 0;
149 mod->pad = 0;
150 mod++;
151 }
152
153 done:
154 drm_object_attach_property(&plane->base, config->modifiers_property,
155 blob->base.id);
156
157 return 0;
158 }
159
160 /**
161 * drm_universal_plane_init - Initialize a new universal plane object
162 * @dev: DRM device
163 * @plane: plane object to init
164 * @possible_crtcs: bitmask of possible CRTCs
165 * @funcs: callbacks for the new plane
166 * @formats: array of supported formats (DRM_FORMAT\_\*)
167 * @format_count: number of elements in @formats
168 * @format_modifiers: array of struct drm_format modifiers terminated by
169 * DRM_FORMAT_MOD_INVALID
170 * @type: type of plane (overlay, primary, cursor)
171 * @name: printf style format string for the plane name, or NULL for default name
172 *
173 * Initializes a plane object of type @type.
174 *
175 * Returns:
176 * Zero on success, error code on failure.
177 */
drm_universal_plane_init(struct drm_device * dev,struct drm_plane * plane,uint32_t possible_crtcs,const struct drm_plane_funcs * funcs,const uint32_t * formats,unsigned int format_count,const uint64_t * format_modifiers,enum drm_plane_type type,const char * name,...)178 int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
179 uint32_t possible_crtcs,
180 const struct drm_plane_funcs *funcs,
181 const uint32_t *formats, unsigned int format_count,
182 const uint64_t *format_modifiers,
183 enum drm_plane_type type,
184 const char *name, ...)
185 {
186 struct drm_mode_config *config = &dev->mode_config;
187 unsigned int format_modifier_count = 0;
188 int ret;
189
190 /* plane index is used with 32bit bitmasks */
191 if (WARN_ON(config->num_total_plane >= 32))
192 return -EINVAL;
193
194 WARN_ON(drm_drv_uses_atomic_modeset(dev) &&
195 (!funcs->atomic_destroy_state ||
196 !funcs->atomic_duplicate_state));
197
198 ret = drm_mode_object_add(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
199 if (ret)
200 return ret;
201
202 drm_modeset_lock_init(&plane->mutex);
203
204 plane->base.properties = &plane->properties;
205 plane->dev = dev;
206 plane->funcs = funcs;
207 plane->format_types = kmalloc_array(format_count, sizeof(uint32_t),
208 GFP_KERNEL);
209 if (!plane->format_types) {
210 DRM_DEBUG_KMS("out of memory when allocating plane\n");
211 drm_mode_object_unregister(dev, &plane->base);
212 return -ENOMEM;
213 }
214
215 /*
216 * First driver to need more than 64 formats needs to fix this. Each
217 * format is encoded as a bit and the current code only supports a u64.
218 */
219 if (WARN_ON(format_count > 64))
220 return -EINVAL;
221
222 if (format_modifiers) {
223 const uint64_t *temp_modifiers = format_modifiers;
224 while (*temp_modifiers++ != DRM_FORMAT_MOD_INVALID)
225 format_modifier_count++;
226 }
227
228 if (format_modifier_count)
229 config->allow_fb_modifiers = true;
230
231 plane->modifier_count = format_modifier_count;
232 plane->modifiers = kmalloc_array(format_modifier_count,
233 sizeof(format_modifiers[0]),
234 GFP_KERNEL);
235
236 if (format_modifier_count && !plane->modifiers) {
237 DRM_DEBUG_KMS("out of memory when allocating plane\n");
238 kfree(plane->format_types);
239 drm_mode_object_unregister(dev, &plane->base);
240 return -ENOMEM;
241 }
242
243 if (name) {
244 va_list ap;
245
246 va_start(ap, name);
247 plane->name = kvasprintf(GFP_KERNEL, name, ap);
248 va_end(ap);
249 } else {
250 plane->name = kasprintf(GFP_KERNEL, "plane-%d",
251 drm_num_planes(dev));
252 }
253 if (!plane->name) {
254 kfree(plane->format_types);
255 kfree(plane->modifiers);
256 drm_mode_object_unregister(dev, &plane->base);
257 return -ENOMEM;
258 }
259
260 memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
261 plane->format_count = format_count;
262 memcpy(plane->modifiers, format_modifiers,
263 format_modifier_count * sizeof(format_modifiers[0]));
264 plane->possible_crtcs = possible_crtcs;
265 plane->type = type;
266
267 list_add_tail(&plane->head, &config->plane_list);
268 plane->index = config->num_total_plane++;
269
270 drm_object_attach_property(&plane->base,
271 config->plane_type_property,
272 plane->type);
273
274 if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
275 drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
276 drm_object_attach_property(&plane->base, config->prop_in_fence_fd, -1);
277 drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
278 drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
279 drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
280 drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
281 drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
282 drm_object_attach_property(&plane->base, config->prop_src_x, 0);
283 drm_object_attach_property(&plane->base, config->prop_src_y, 0);
284 drm_object_attach_property(&plane->base, config->prop_src_w, 0);
285 drm_object_attach_property(&plane->base, config->prop_src_h, 0);
286 }
287
288 if (config->allow_fb_modifiers)
289 create_in_format_blob(dev, plane);
290
291 return 0;
292 }
293 EXPORT_SYMBOL(drm_universal_plane_init);
294
drm_plane_register_all(struct drm_device * dev)295 int drm_plane_register_all(struct drm_device *dev)
296 {
297 struct drm_plane *plane;
298 int ret = 0;
299
300 drm_for_each_plane(plane, dev) {
301 if (plane->funcs->late_register)
302 ret = plane->funcs->late_register(plane);
303 if (ret)
304 return ret;
305 }
306
307 return 0;
308 }
309
drm_plane_unregister_all(struct drm_device * dev)310 void drm_plane_unregister_all(struct drm_device *dev)
311 {
312 struct drm_plane *plane;
313
314 drm_for_each_plane(plane, dev) {
315 if (plane->funcs->early_unregister)
316 plane->funcs->early_unregister(plane);
317 }
318 }
319
320 /**
321 * drm_plane_init - Initialize a legacy plane
322 * @dev: DRM device
323 * @plane: plane object to init
324 * @possible_crtcs: bitmask of possible CRTCs
325 * @funcs: callbacks for the new plane
326 * @formats: array of supported formats (DRM_FORMAT\_\*)
327 * @format_count: number of elements in @formats
328 * @is_primary: plane type (primary vs overlay)
329 *
330 * Legacy API to initialize a DRM plane.
331 *
332 * New drivers should call drm_universal_plane_init() instead.
333 *
334 * Returns:
335 * Zero on success, error code on failure.
336 */
drm_plane_init(struct drm_device * dev,struct drm_plane * plane,uint32_t possible_crtcs,const struct drm_plane_funcs * funcs,const uint32_t * formats,unsigned int format_count,bool is_primary)337 int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
338 uint32_t possible_crtcs,
339 const struct drm_plane_funcs *funcs,
340 const uint32_t *formats, unsigned int format_count,
341 bool is_primary)
342 {
343 enum drm_plane_type type;
344
345 type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
346 return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
347 formats, format_count,
348 NULL, type, NULL);
349 }
350 EXPORT_SYMBOL(drm_plane_init);
351
352 /**
353 * drm_plane_cleanup - Clean up the core plane usage
354 * @plane: plane to cleanup
355 *
356 * This function cleans up @plane and removes it from the DRM mode setting
357 * core. Note that the function does *not* free the plane structure itself,
358 * this is the responsibility of the caller.
359 */
drm_plane_cleanup(struct drm_plane * plane)360 void drm_plane_cleanup(struct drm_plane *plane)
361 {
362 struct drm_device *dev = plane->dev;
363
364 drm_modeset_lock_fini(&plane->mutex);
365
366 kfree(plane->format_types);
367 kfree(plane->modifiers);
368 drm_mode_object_unregister(dev, &plane->base);
369
370 BUG_ON(list_empty(&plane->head));
371
372 /* Note that the plane_list is considered to be static; should we
373 * remove the drm_plane at runtime we would have to decrement all
374 * the indices on the drm_plane after us in the plane_list.
375 */
376
377 list_del(&plane->head);
378 dev->mode_config.num_total_plane--;
379
380 WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
381 if (plane->state && plane->funcs->atomic_destroy_state)
382 plane->funcs->atomic_destroy_state(plane, plane->state);
383
384 kfree(plane->name);
385
386 memset(plane, 0, sizeof(*plane));
387 }
388 EXPORT_SYMBOL(drm_plane_cleanup);
389
390 /**
391 * drm_plane_from_index - find the registered plane at an index
392 * @dev: DRM device
393 * @idx: index of registered plane to find for
394 *
395 * Given a plane index, return the registered plane from DRM device's
396 * list of planes with matching index. This is the inverse of drm_plane_index().
397 */
398 struct drm_plane *
drm_plane_from_index(struct drm_device * dev,int idx)399 drm_plane_from_index(struct drm_device *dev, int idx)
400 {
401 struct drm_plane *plane;
402
403 drm_for_each_plane(plane, dev)
404 if (idx == plane->index)
405 return plane;
406
407 return NULL;
408 }
409 EXPORT_SYMBOL(drm_plane_from_index);
410
411 /**
412 * drm_plane_force_disable - Forcibly disable a plane
413 * @plane: plane to disable
414 *
415 * Forces the plane to be disabled.
416 *
417 * Used when the plane's current framebuffer is destroyed,
418 * and when restoring fbdev mode.
419 *
420 * Note that this function is not suitable for atomic drivers, since it doesn't
421 * wire through the lock acquisition context properly and hence can't handle
422 * retries or driver private locks. You probably want to use
423 * drm_atomic_helper_disable_plane() or
424 * drm_atomic_helper_disable_planes_on_crtc() instead.
425 */
drm_plane_force_disable(struct drm_plane * plane)426 void drm_plane_force_disable(struct drm_plane *plane)
427 {
428 int ret;
429
430 if (!plane->fb)
431 return;
432
433 WARN_ON(drm_drv_uses_atomic_modeset(plane->dev));
434
435 plane->old_fb = plane->fb;
436 ret = plane->funcs->disable_plane(plane, NULL);
437 if (ret) {
438 DRM_ERROR("failed to disable plane with busy fb\n");
439 plane->old_fb = NULL;
440 return;
441 }
442 /* disconnect the plane from the fb and crtc: */
443 drm_framebuffer_put(plane->old_fb);
444 plane->old_fb = NULL;
445 plane->fb = NULL;
446 plane->crtc = NULL;
447 }
448 EXPORT_SYMBOL(drm_plane_force_disable);
449
450 /**
451 * drm_mode_plane_set_obj_prop - set the value of a property
452 * @plane: drm plane object to set property value for
453 * @property: property to set
454 * @value: value the property should be set to
455 *
456 * This functions sets a given property on a given plane object. This function
457 * calls the driver's ->set_property callback and changes the software state of
458 * the property if the callback succeeds.
459 *
460 * Returns:
461 * Zero on success, error code on failure.
462 */
drm_mode_plane_set_obj_prop(struct drm_plane * plane,struct drm_property * property,uint64_t value)463 int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
464 struct drm_property *property,
465 uint64_t value)
466 {
467 int ret = -EINVAL;
468 struct drm_mode_object *obj = &plane->base;
469
470 if (plane->funcs->set_property)
471 ret = plane->funcs->set_property(plane, property, value);
472 if (!ret)
473 drm_object_property_set_value(obj, property, value);
474
475 return ret;
476 }
477 EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
478
drm_mode_getplane_res(struct drm_device * dev,void * data,struct drm_file * file_priv)479 int drm_mode_getplane_res(struct drm_device *dev, void *data,
480 struct drm_file *file_priv)
481 {
482 struct drm_mode_get_plane_res *plane_resp = data;
483 struct drm_plane *plane;
484 uint32_t __user *plane_ptr;
485 int count = 0;
486
487 if (!drm_core_check_feature(dev, DRIVER_MODESET))
488 return -EOPNOTSUPP;
489
490 plane_ptr = u64_to_user_ptr(plane_resp->plane_id_ptr);
491
492 /*
493 * This ioctl is called twice, once to determine how much space is
494 * needed, and the 2nd time to fill it.
495 */
496 drm_for_each_plane(plane, dev) {
497 /*
498 * Unless userspace set the 'universal planes'
499 * capability bit, only advertise overlays.
500 */
501 if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
502 !file_priv->universal_planes)
503 continue;
504
505 if (drm_lease_held(file_priv, plane->base.id)) {
506 if (count < plane_resp->count_planes &&
507 put_user(plane->base.id, plane_ptr + count))
508 return -EFAULT;
509 count++;
510 }
511 }
512 plane_resp->count_planes = count;
513
514 return 0;
515 }
516
drm_mode_getplane(struct drm_device * dev,void * data,struct drm_file * file_priv)517 int drm_mode_getplane(struct drm_device *dev, void *data,
518 struct drm_file *file_priv)
519 {
520 struct drm_mode_get_plane *plane_resp = data;
521 struct drm_plane *plane;
522 uint32_t __user *format_ptr;
523
524 if (!drm_core_check_feature(dev, DRIVER_MODESET))
525 return -EOPNOTSUPP;
526
527 plane = drm_plane_find(dev, file_priv, plane_resp->plane_id);
528 if (!plane)
529 return -ENOENT;
530
531 drm_modeset_lock(&plane->mutex, NULL);
532 if (plane->state && plane->state->crtc && drm_lease_held(file_priv, plane->state->crtc->base.id))
533 plane_resp->crtc_id = plane->state->crtc->base.id;
534 else if (!plane->state && plane->crtc && drm_lease_held(file_priv, plane->crtc->base.id))
535 plane_resp->crtc_id = plane->crtc->base.id;
536 else
537 plane_resp->crtc_id = 0;
538
539 if (plane->state && plane->state->fb)
540 plane_resp->fb_id = plane->state->fb->base.id;
541 else if (!plane->state && plane->fb)
542 plane_resp->fb_id = plane->fb->base.id;
543 else
544 plane_resp->fb_id = 0;
545 drm_modeset_unlock(&plane->mutex);
546
547 plane_resp->plane_id = plane->base.id;
548 plane_resp->possible_crtcs = drm_lease_filter_crtcs(file_priv,
549 plane->possible_crtcs);
550
551 plane_resp->gamma_size = 0;
552
553 /*
554 * This ioctl is called twice, once to determine how much space is
555 * needed, and the 2nd time to fill it.
556 */
557 if (plane->format_count &&
558 (plane_resp->count_format_types >= plane->format_count)) {
559 format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;
560 if (copy_to_user(format_ptr,
561 plane->format_types,
562 sizeof(uint32_t) * plane->format_count)) {
563 return -EFAULT;
564 }
565 }
566 plane_resp->count_format_types = plane->format_count;
567
568 return 0;
569 }
570
drm_plane_check_pixel_format(struct drm_plane * plane,u32 format,u64 modifier)571 int drm_plane_check_pixel_format(struct drm_plane *plane,
572 u32 format, u64 modifier)
573 {
574 unsigned int i;
575
576 for (i = 0; i < plane->format_count; i++) {
577 if (format == plane->format_types[i])
578 break;
579 }
580 if (i == plane->format_count)
581 return -EINVAL;
582
583 if (plane->funcs->format_mod_supported) {
584 if (!plane->funcs->format_mod_supported(plane, format, modifier))
585 return -EINVAL;
586 } else {
587 if (!plane->modifier_count)
588 return 0;
589
590 for (i = 0; i < plane->modifier_count; i++) {
591 if (modifier == plane->modifiers[i])
592 break;
593 }
594 if (i == plane->modifier_count)
595 return -EINVAL;
596 }
597
598 return 0;
599 }
600
__setplane_check(struct drm_plane * plane,struct drm_crtc * crtc,struct drm_framebuffer * fb,int32_t crtc_x,int32_t crtc_y,uint32_t crtc_w,uint32_t crtc_h,uint32_t src_x,uint32_t src_y,uint32_t src_w,uint32_t src_h)601 static int __setplane_check(struct drm_plane *plane,
602 struct drm_crtc *crtc,
603 struct drm_framebuffer *fb,
604 int32_t crtc_x, int32_t crtc_y,
605 uint32_t crtc_w, uint32_t crtc_h,
606 uint32_t src_x, uint32_t src_y,
607 uint32_t src_w, uint32_t src_h)
608 {
609 int ret;
610
611 /* Check whether this plane is usable on this CRTC */
612 if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) {
613 DRM_DEBUG_KMS("Invalid crtc for plane\n");
614 return -EINVAL;
615 }
616
617 /* Check whether this plane supports the fb pixel format. */
618 ret = drm_plane_check_pixel_format(plane, fb->format->format,
619 fb->modifier);
620 if (ret) {
621 struct drm_format_name_buf format_name;
622
623 DRM_DEBUG_KMS("Invalid pixel format %s, modifier 0x%"PRIx64"\n",
624 drm_get_format_name(fb->format->format,
625 &format_name),
626 fb->modifier);
627 return ret;
628 }
629
630 /* Give drivers some help against integer overflows */
631 if (crtc_w > INT_MAX ||
632 crtc_x > INT_MAX - (int32_t) crtc_w ||
633 crtc_h > INT_MAX ||
634 crtc_y > INT_MAX - (int32_t) crtc_h) {
635 DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
636 crtc_w, crtc_h, crtc_x, crtc_y);
637 return -ERANGE;
638 }
639
640 ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb);
641 if (ret)
642 return ret;
643
644 return 0;
645 }
646
647 /**
648 * drm_any_plane_has_format - Check whether any plane supports this format and modifier combination
649 * @dev: DRM device
650 * @format: pixel format (DRM_FORMAT_*)
651 * @modifier: data layout modifier
652 *
653 * Returns:
654 * Whether at least one plane supports the specified format and modifier combination.
655 */
drm_any_plane_has_format(struct drm_device * dev,u32 format,u64 modifier)656 bool drm_any_plane_has_format(struct drm_device *dev,
657 u32 format, u64 modifier)
658 {
659 struct drm_plane *plane;
660
661 drm_for_each_plane(plane, dev) {
662 if (drm_plane_check_pixel_format(plane, format, modifier) == 0)
663 return true;
664 }
665
666 return false;
667 }
668 EXPORT_SYMBOL(drm_any_plane_has_format);
669
670 /*
671 * __setplane_internal - setplane handler for internal callers
672 *
673 * This function will take a reference on the new fb for the plane
674 * on success.
675 *
676 * src_{x,y,w,h} are provided in 16.16 fixed point format
677 */
__setplane_internal(struct drm_plane * plane,struct drm_crtc * crtc,struct drm_framebuffer * fb,int32_t crtc_x,int32_t crtc_y,uint32_t crtc_w,uint32_t crtc_h,uint32_t src_x,uint32_t src_y,uint32_t src_w,uint32_t src_h,struct drm_modeset_acquire_ctx * ctx)678 static int __setplane_internal(struct drm_plane *plane,
679 struct drm_crtc *crtc,
680 struct drm_framebuffer *fb,
681 int32_t crtc_x, int32_t crtc_y,
682 uint32_t crtc_w, uint32_t crtc_h,
683 /* src_{x,y,w,h} values are 16.16 fixed point */
684 uint32_t src_x, uint32_t src_y,
685 uint32_t src_w, uint32_t src_h,
686 struct drm_modeset_acquire_ctx *ctx)
687 {
688 int ret = 0;
689
690 WARN_ON(drm_drv_uses_atomic_modeset(plane->dev));
691
692 /* No fb means shut it down */
693 if (!fb) {
694 plane->old_fb = plane->fb;
695 ret = plane->funcs->disable_plane(plane, ctx);
696 if (!ret) {
697 plane->crtc = NULL;
698 plane->fb = NULL;
699 } else {
700 plane->old_fb = NULL;
701 }
702 goto out;
703 }
704
705 ret = __setplane_check(plane, crtc, fb,
706 crtc_x, crtc_y, crtc_w, crtc_h,
707 src_x, src_y, src_w, src_h);
708 if (ret)
709 goto out;
710
711 plane->old_fb = plane->fb;
712 ret = plane->funcs->update_plane(plane, crtc, fb,
713 crtc_x, crtc_y, crtc_w, crtc_h,
714 src_x, src_y, src_w, src_h, ctx);
715 if (!ret) {
716 plane->crtc = crtc;
717 plane->fb = fb;
718 drm_framebuffer_get(plane->fb);
719 } else {
720 plane->old_fb = NULL;
721 }
722
723 out:
724 if (plane->old_fb)
725 drm_framebuffer_put(plane->old_fb);
726 plane->old_fb = NULL;
727
728 return ret;
729 }
730
__setplane_atomic(struct drm_plane * plane,struct drm_crtc * crtc,struct drm_framebuffer * fb,int32_t crtc_x,int32_t crtc_y,uint32_t crtc_w,uint32_t crtc_h,uint32_t src_x,uint32_t src_y,uint32_t src_w,uint32_t src_h,struct drm_modeset_acquire_ctx * ctx)731 static int __setplane_atomic(struct drm_plane *plane,
732 struct drm_crtc *crtc,
733 struct drm_framebuffer *fb,
734 int32_t crtc_x, int32_t crtc_y,
735 uint32_t crtc_w, uint32_t crtc_h,
736 uint32_t src_x, uint32_t src_y,
737 uint32_t src_w, uint32_t src_h,
738 struct drm_modeset_acquire_ctx *ctx)
739 {
740 int ret;
741
742 WARN_ON(!drm_drv_uses_atomic_modeset(plane->dev));
743
744 /* No fb means shut it down */
745 if (!fb)
746 return plane->funcs->disable_plane(plane, ctx);
747
748 /*
749 * FIXME: This is redundant with drm_atomic_plane_check(),
750 * but the legacy cursor/"async" .update_plane() tricks
751 * don't call that so we still need this here. Should remove
752 * this when all .update_plane() implementations have been
753 * fixed to call drm_atomic_plane_check().
754 */
755 ret = __setplane_check(plane, crtc, fb,
756 crtc_x, crtc_y, crtc_w, crtc_h,
757 src_x, src_y, src_w, src_h);
758 if (ret)
759 return ret;
760
761 return plane->funcs->update_plane(plane, crtc, fb,
762 crtc_x, crtc_y, crtc_w, crtc_h,
763 src_x, src_y, src_w, src_h, ctx);
764 }
765
setplane_internal(struct drm_plane * plane,struct drm_crtc * crtc,struct drm_framebuffer * fb,int32_t crtc_x,int32_t crtc_y,uint32_t crtc_w,uint32_t crtc_h,uint32_t src_x,uint32_t src_y,uint32_t src_w,uint32_t src_h)766 static int setplane_internal(struct drm_plane *plane,
767 struct drm_crtc *crtc,
768 struct drm_framebuffer *fb,
769 int32_t crtc_x, int32_t crtc_y,
770 uint32_t crtc_w, uint32_t crtc_h,
771 /* src_{x,y,w,h} values are 16.16 fixed point */
772 uint32_t src_x, uint32_t src_y,
773 uint32_t src_w, uint32_t src_h)
774 {
775 struct drm_modeset_acquire_ctx ctx;
776 int ret;
777
778 DRM_MODESET_LOCK_ALL_BEGIN(plane->dev, ctx,
779 DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);
780
781 if (drm_drv_uses_atomic_modeset(plane->dev))
782 ret = __setplane_atomic(plane, crtc, fb,
783 crtc_x, crtc_y, crtc_w, crtc_h,
784 src_x, src_y, src_w, src_h, &ctx);
785 else
786 ret = __setplane_internal(plane, crtc, fb,
787 crtc_x, crtc_y, crtc_w, crtc_h,
788 src_x, src_y, src_w, src_h, &ctx);
789
790 DRM_MODESET_LOCK_ALL_END(ctx, ret);
791
792 return ret;
793 }
794
drm_mode_setplane(struct drm_device * dev,void * data,struct drm_file * file_priv)795 int drm_mode_setplane(struct drm_device *dev, void *data,
796 struct drm_file *file_priv)
797 {
798 struct drm_mode_set_plane *plane_req = data;
799 struct drm_plane *plane;
800 struct drm_crtc *crtc = NULL;
801 struct drm_framebuffer *fb = NULL;
802 int ret;
803
804 if (!drm_core_check_feature(dev, DRIVER_MODESET))
805 return -EOPNOTSUPP;
806
807 /*
808 * First, find the plane, crtc, and fb objects. If not available,
809 * we don't bother to call the driver.
810 */
811 plane = drm_plane_find(dev, file_priv, plane_req->plane_id);
812 if (!plane) {
813 DRM_DEBUG_KMS("Unknown plane ID %d\n",
814 plane_req->plane_id);
815 return -ENOENT;
816 }
817
818 if (plane_req->fb_id) {
819 fb = drm_framebuffer_lookup(dev, file_priv, plane_req->fb_id);
820 if (!fb) {
821 DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
822 plane_req->fb_id);
823 return -ENOENT;
824 }
825
826 crtc = drm_crtc_find(dev, file_priv, plane_req->crtc_id);
827 if (!crtc) {
828 drm_framebuffer_put(fb);
829 DRM_DEBUG_KMS("Unknown crtc ID %d\n",
830 plane_req->crtc_id);
831 return -ENOENT;
832 }
833 }
834
835 ret = setplane_internal(plane, crtc, fb,
836 plane_req->crtc_x, plane_req->crtc_y,
837 plane_req->crtc_w, plane_req->crtc_h,
838 plane_req->src_x, plane_req->src_y,
839 plane_req->src_w, plane_req->src_h);
840
841 if (fb)
842 drm_framebuffer_put(fb);
843
844 return ret;
845 }
846
drm_mode_cursor_universal(struct drm_crtc * crtc,struct drm_mode_cursor2 * req,struct drm_file * file_priv,struct drm_modeset_acquire_ctx * ctx)847 static int drm_mode_cursor_universal(struct drm_crtc *crtc,
848 struct drm_mode_cursor2 *req,
849 struct drm_file *file_priv,
850 struct drm_modeset_acquire_ctx *ctx)
851 {
852 struct drm_device *dev = crtc->dev;
853 struct drm_plane *plane = crtc->cursor;
854 struct drm_framebuffer *fb = NULL;
855 struct drm_mode_fb_cmd2 fbreq = {
856 .width = req->width,
857 .height = req->height,
858 .pixel_format = DRM_FORMAT_ARGB8888,
859 .pitches = { req->width * 4 },
860 .handles = { req->handle },
861 };
862 int32_t crtc_x, crtc_y;
863 uint32_t crtc_w = 0, crtc_h = 0;
864 uint32_t src_w = 0, src_h = 0;
865 int ret = 0;
866
867 BUG_ON(!plane);
868 WARN_ON(plane->crtc != crtc && plane->crtc != NULL);
869
870 /*
871 * Obtain fb we'll be using (either new or existing) and take an extra
872 * reference to it if fb != null. setplane will take care of dropping
873 * the reference if the plane update fails.
874 */
875 if (req->flags & DRM_MODE_CURSOR_BO) {
876 if (req->handle) {
877 fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv);
878 if (IS_ERR(fb)) {
879 DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
880 return PTR_ERR(fb);
881 }
882
883 fb->hot_x = req->hot_x;
884 fb->hot_y = req->hot_y;
885 } else {
886 fb = NULL;
887 }
888 } else {
889 if (plane->state)
890 fb = plane->state->fb;
891 else
892 fb = plane->fb;
893
894 if (fb)
895 drm_framebuffer_get(fb);
896 }
897
898 if (req->flags & DRM_MODE_CURSOR_MOVE) {
899 crtc_x = req->x;
900 crtc_y = req->y;
901 } else {
902 crtc_x = crtc->cursor_x;
903 crtc_y = crtc->cursor_y;
904 }
905
906 if (fb) {
907 crtc_w = fb->width;
908 crtc_h = fb->height;
909 src_w = fb->width << 16;
910 src_h = fb->height << 16;
911 }
912
913 if (drm_drv_uses_atomic_modeset(dev))
914 ret = __setplane_atomic(plane, crtc, fb,
915 crtc_x, crtc_y, crtc_w, crtc_h,
916 0, 0, src_w, src_h, ctx);
917 else
918 ret = __setplane_internal(plane, crtc, fb,
919 crtc_x, crtc_y, crtc_w, crtc_h,
920 0, 0, src_w, src_h, ctx);
921
922 if (fb)
923 drm_framebuffer_put(fb);
924
925 /* Update successful; save new cursor position, if necessary */
926 if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) {
927 crtc->cursor_x = req->x;
928 crtc->cursor_y = req->y;
929 }
930
931 return ret;
932 }
933
drm_mode_cursor_common(struct drm_device * dev,struct drm_mode_cursor2 * req,struct drm_file * file_priv)934 static int drm_mode_cursor_common(struct drm_device *dev,
935 struct drm_mode_cursor2 *req,
936 struct drm_file *file_priv)
937 {
938 struct drm_crtc *crtc;
939 struct drm_modeset_acquire_ctx ctx;
940 int ret = 0;
941
942 if (!drm_core_check_feature(dev, DRIVER_MODESET))
943 return -EOPNOTSUPP;
944
945 if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
946 return -EINVAL;
947
948 crtc = drm_crtc_find(dev, file_priv, req->crtc_id);
949 if (!crtc) {
950 DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
951 return -ENOENT;
952 }
953
954 drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
955 retry:
956 ret = drm_modeset_lock(&crtc->mutex, &ctx);
957 if (ret)
958 goto out;
959 /*
960 * If this crtc has a universal cursor plane, call that plane's update
961 * handler rather than using legacy cursor handlers.
962 */
963 if (crtc->cursor) {
964 ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx);
965 if (ret)
966 goto out;
967
968 if (!drm_lease_held(file_priv, crtc->cursor->base.id)) {
969 ret = -EACCES;
970 goto out;
971 }
972
973 ret = drm_mode_cursor_universal(crtc, req, file_priv, &ctx);
974 goto out;
975 }
976
977 if (req->flags & DRM_MODE_CURSOR_BO) {
978 if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
979 ret = -ENXIO;
980 goto out;
981 }
982 /* Turns off the cursor if handle is 0 */
983 if (crtc->funcs->cursor_set2)
984 ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle,
985 req->width, req->height, req->hot_x, req->hot_y);
986 else
987 ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
988 req->width, req->height);
989 }
990
991 if (req->flags & DRM_MODE_CURSOR_MOVE) {
992 if (crtc->funcs->cursor_move) {
993 ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
994 } else {
995 ret = -EFAULT;
996 goto out;
997 }
998 }
999 out:
1000 if (ret == -EDEADLK) {
1001 ret = drm_modeset_backoff(&ctx);
1002 if (!ret)
1003 goto retry;
1004 }
1005
1006 drm_modeset_drop_locks(&ctx);
1007 drm_modeset_acquire_fini(&ctx);
1008
1009 return ret;
1010
1011 }
1012
1013
drm_mode_cursor_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)1014 int drm_mode_cursor_ioctl(struct drm_device *dev,
1015 void *data, struct drm_file *file_priv)
1016 {
1017 struct drm_mode_cursor *req = data;
1018 struct drm_mode_cursor2 new_req;
1019
1020 memcpy(&new_req, req, sizeof(struct drm_mode_cursor));
1021 new_req.hot_x = new_req.hot_y = 0;
1022
1023 return drm_mode_cursor_common(dev, &new_req, file_priv);
1024 }
1025
1026 /*
1027 * Set the cursor configuration based on user request. This implements the 2nd
1028 * version of the cursor ioctl, which allows userspace to additionally specify
1029 * the hotspot of the pointer.
1030 */
drm_mode_cursor2_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)1031 int drm_mode_cursor2_ioctl(struct drm_device *dev,
1032 void *data, struct drm_file *file_priv)
1033 {
1034 struct drm_mode_cursor2 *req = data;
1035
1036 return drm_mode_cursor_common(dev, req, file_priv);
1037 }
1038
drm_mode_page_flip_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)1039 int drm_mode_page_flip_ioctl(struct drm_device *dev,
1040 void *data, struct drm_file *file_priv)
1041 {
1042 struct drm_mode_crtc_page_flip_target *page_flip = data;
1043 struct drm_crtc *crtc;
1044 struct drm_plane *plane;
1045 struct drm_framebuffer *fb = NULL, *old_fb;
1046 struct drm_pending_vblank_event *e = NULL;
1047 u32 target_vblank = page_flip->sequence;
1048 struct drm_modeset_acquire_ctx ctx;
1049 int ret = -EINVAL;
1050
1051 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1052 return -EOPNOTSUPP;
1053
1054 if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS)
1055 return -EINVAL;
1056
1057 if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET))
1058 return -EINVAL;
1059
1060 /* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags
1061 * can be specified
1062 */
1063 if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET)
1064 return -EINVAL;
1065
1066 if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
1067 return -EINVAL;
1068
1069 crtc = drm_crtc_find(dev, file_priv, page_flip->crtc_id);
1070 if (!crtc)
1071 return -ENOENT;
1072
1073 plane = crtc->primary;
1074
1075 if (!drm_lease_held(file_priv, plane->base.id))
1076 return -EACCES;
1077
1078 if (crtc->funcs->page_flip_target) {
1079 u32 current_vblank;
1080 int r;
1081
1082 r = drm_crtc_vblank_get(crtc);
1083 if (r)
1084 return r;
1085
1086 current_vblank = (u32)drm_crtc_vblank_count(crtc);
1087
1088 switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) {
1089 case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE:
1090 if ((int)(target_vblank - current_vblank) > 1) {
1091 DRM_DEBUG("Invalid absolute flip target %u, "
1092 "must be <= %u\n", target_vblank,
1093 current_vblank + 1);
1094 drm_crtc_vblank_put(crtc);
1095 return -EINVAL;
1096 }
1097 break;
1098 case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE:
1099 if (target_vblank != 0 && target_vblank != 1) {
1100 DRM_DEBUG("Invalid relative flip target %u, "
1101 "must be 0 or 1\n", target_vblank);
1102 drm_crtc_vblank_put(crtc);
1103 return -EINVAL;
1104 }
1105 target_vblank += current_vblank;
1106 break;
1107 default:
1108 target_vblank = current_vblank +
1109 !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC);
1110 break;
1111 }
1112 } else if (crtc->funcs->page_flip == NULL ||
1113 (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) {
1114 return -EINVAL;
1115 }
1116
1117 drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
1118 retry:
1119 ret = drm_modeset_lock(&crtc->mutex, &ctx);
1120 if (ret)
1121 goto out;
1122 ret = drm_modeset_lock(&plane->mutex, &ctx);
1123 if (ret)
1124 goto out;
1125
1126 if (plane->state)
1127 old_fb = plane->state->fb;
1128 else
1129 old_fb = plane->fb;
1130
1131 if (old_fb == NULL) {
1132 /* The framebuffer is currently unbound, presumably
1133 * due to a hotplug event, that userspace has not
1134 * yet discovered.
1135 */
1136 ret = -EBUSY;
1137 goto out;
1138 }
1139
1140 fb = drm_framebuffer_lookup(dev, file_priv, page_flip->fb_id);
1141 if (!fb) {
1142 ret = -ENOENT;
1143 goto out;
1144 }
1145
1146 if (plane->state) {
1147 const struct drm_plane_state *state = plane->state;
1148
1149 ret = drm_framebuffer_check_src_coords(state->src_x,
1150 state->src_y,
1151 state->src_w,
1152 state->src_h,
1153 fb);
1154 } else {
1155 ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y,
1156 &crtc->mode, fb);
1157 }
1158 if (ret)
1159 goto out;
1160
1161 if (old_fb->format != fb->format) {
1162 DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
1163 ret = -EINVAL;
1164 goto out;
1165 }
1166
1167 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
1168 e = kzalloc(sizeof *e, GFP_KERNEL);
1169 if (!e) {
1170 ret = -ENOMEM;
1171 goto out;
1172 }
1173
1174 e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
1175 e->event.base.length = sizeof(e->event);
1176 e->event.vbl.user_data = page_flip->user_data;
1177 e->event.vbl.crtc_id = crtc->base.id;
1178
1179 ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
1180 if (ret) {
1181 kfree(e);
1182 e = NULL;
1183 goto out;
1184 }
1185 }
1186
1187 plane->old_fb = plane->fb;
1188 if (crtc->funcs->page_flip_target)
1189 ret = crtc->funcs->page_flip_target(crtc, fb, e,
1190 page_flip->flags,
1191 target_vblank,
1192 &ctx);
1193 else
1194 ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags,
1195 &ctx);
1196 if (ret) {
1197 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT)
1198 drm_event_cancel_free(dev, &e->base);
1199 /* Keep the old fb, don't unref it. */
1200 plane->old_fb = NULL;
1201 } else {
1202 if (!plane->state) {
1203 plane->fb = fb;
1204 drm_framebuffer_get(fb);
1205 }
1206 }
1207
1208 out:
1209 if (fb)
1210 drm_framebuffer_put(fb);
1211 if (plane->old_fb)
1212 drm_framebuffer_put(plane->old_fb);
1213 plane->old_fb = NULL;
1214
1215 if (ret == -EDEADLK) {
1216 ret = drm_modeset_backoff(&ctx);
1217 if (!ret)
1218 goto retry;
1219 }
1220
1221 drm_modeset_drop_locks(&ctx);
1222 drm_modeset_acquire_fini(&ctx);
1223
1224 if (ret && crtc->funcs->page_flip_target)
1225 drm_crtc_vblank_put(crtc);
1226
1227 return ret;
1228 }
1229