1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/slab.h>
24#include <linux/uaccess.h>
25
26#include <drm/drm_plane.h>
27#include <drm/drm_drv.h>
28#include <drm/drm_print.h>
29#include <drm/drm_framebuffer.h>
30#include <drm/drm_file.h>
31#include <drm/drm_crtc.h>
32#include <drm/drm_fourcc.h>
33#include <drm/drm_managed.h>
34#include <drm/drm_vblank.h>
35
36#include "drm_crtc_internal.h"
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140static unsigned int drm_num_planes(struct drm_device *dev)
141{
142 unsigned int num = 0;
143 struct drm_plane *tmp;
144
145 drm_for_each_plane(tmp, dev) {
146 num++;
147 }
148
149 return num;
150}
151
152static inline u32 *
153formats_ptr(struct drm_format_modifier_blob *blob)
154{
155 return (u32 *)(((char *)blob) + blob->formats_offset);
156}
157
158static inline struct drm_format_modifier *
159modifiers_ptr(struct drm_format_modifier_blob *blob)
160{
161 return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
162}
163
164static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane)
165{
166 const struct drm_mode_config *config = &dev->mode_config;
167 struct drm_property_blob *blob;
168 struct drm_format_modifier *mod;
169 size_t blob_size, formats_size, modifiers_size;
170 struct drm_format_modifier_blob *blob_data;
171 unsigned int i, j;
172
173 formats_size = sizeof(__u32) * plane->format_count;
174 if (WARN_ON(!formats_size)) {
175
176 return 0;
177 }
178
179 modifiers_size =
180 sizeof(struct drm_format_modifier) * plane->modifier_count;
181
182 blob_size = sizeof(struct drm_format_modifier_blob);
183
184
185
186 BUILD_BUG_ON(sizeof(struct drm_format_modifier_blob) % 8);
187 blob_size += ALIGN(formats_size, 8);
188 blob_size += modifiers_size;
189
190 blob = drm_property_create_blob(dev, blob_size, NULL);
191 if (IS_ERR(blob))
192 return -1;
193
194 blob_data = blob->data;
195 blob_data->version = FORMAT_BLOB_CURRENT;
196 blob_data->count_formats = plane->format_count;
197 blob_data->formats_offset = sizeof(struct drm_format_modifier_blob);
198 blob_data->count_modifiers = plane->modifier_count;
199
200 blob_data->modifiers_offset =
201 ALIGN(blob_data->formats_offset + formats_size, 8);
202
203 memcpy(formats_ptr(blob_data), plane->format_types, formats_size);
204
205
206 if (!plane->funcs->format_mod_supported)
207 goto done;
208
209 mod = modifiers_ptr(blob_data);
210 for (i = 0; i < plane->modifier_count; i++) {
211 for (j = 0; j < plane->format_count; j++) {
212 if (plane->funcs->format_mod_supported(plane,
213 plane->format_types[j],
214 plane->modifiers[i])) {
215
216 mod->formats |= 1ULL << j;
217 }
218 }
219
220 mod->modifier = plane->modifiers[i];
221 mod->offset = 0;
222 mod->pad = 0;
223 mod++;
224 }
225
226done:
227 drm_object_attach_property(&plane->base, config->modifiers_property,
228 blob->base.id);
229
230 return 0;
231}
232
233__printf(9, 0)
234static int __drm_universal_plane_init(struct drm_device *dev,
235 struct drm_plane *plane,
236 uint32_t possible_crtcs,
237 const struct drm_plane_funcs *funcs,
238 const uint32_t *formats,
239 unsigned int format_count,
240 const uint64_t *format_modifiers,
241 enum drm_plane_type type,
242 const char *name, va_list ap)
243{
244 struct drm_mode_config *config = &dev->mode_config;
245 unsigned int format_modifier_count = 0;
246 int ret;
247
248
249 if (WARN_ON(config->num_total_plane >= 32))
250 return -EINVAL;
251
252 WARN_ON(drm_drv_uses_atomic_modeset(dev) &&
253 (!funcs->atomic_destroy_state ||
254 !funcs->atomic_duplicate_state));
255
256 ret = drm_mode_object_add(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
257 if (ret)
258 return ret;
259
260 drm_modeset_lock_init(&plane->mutex);
261
262 plane->base.properties = &plane->properties;
263 plane->dev = dev;
264 plane->funcs = funcs;
265 plane->format_types = kmalloc_array(format_count, sizeof(uint32_t),
266 GFP_KERNEL);
267 if (!plane->format_types) {
268 DRM_DEBUG_KMS("out of memory when allocating plane\n");
269 drm_mode_object_unregister(dev, &plane->base);
270 return -ENOMEM;
271 }
272
273
274
275
276
277 if (WARN_ON(format_count > 64))
278 return -EINVAL;
279
280 if (format_modifiers) {
281 const uint64_t *temp_modifiers = format_modifiers;
282
283 while (*temp_modifiers++ != DRM_FORMAT_MOD_INVALID)
284 format_modifier_count++;
285 }
286
287
288 if (format_modifier_count) {
289 drm_WARN_ON(dev, !config->allow_fb_modifiers &&
290 !list_empty(&config->plane_list));
291 config->allow_fb_modifiers = true;
292 } else {
293 drm_WARN_ON(dev, config->allow_fb_modifiers);
294 }
295
296 plane->modifier_count = format_modifier_count;
297 plane->modifiers = kmalloc_array(format_modifier_count,
298 sizeof(format_modifiers[0]),
299 GFP_KERNEL);
300
301 if (format_modifier_count && !plane->modifiers) {
302 DRM_DEBUG_KMS("out of memory when allocating plane\n");
303 kfree(plane->format_types);
304 drm_mode_object_unregister(dev, &plane->base);
305 return -ENOMEM;
306 }
307
308 if (name) {
309 plane->name = kvasprintf(GFP_KERNEL, name, ap);
310 } else {
311 plane->name = kasprintf(GFP_KERNEL, "plane-%d",
312 drm_num_planes(dev));
313 }
314 if (!plane->name) {
315 kfree(plane->format_types);
316 kfree(plane->modifiers);
317 drm_mode_object_unregister(dev, &plane->base);
318 return -ENOMEM;
319 }
320
321 memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
322 plane->format_count = format_count;
323 memcpy(plane->modifiers, format_modifiers,
324 format_modifier_count * sizeof(format_modifiers[0]));
325 plane->possible_crtcs = possible_crtcs;
326 plane->type = type;
327
328 list_add_tail(&plane->head, &config->plane_list);
329 plane->index = config->num_total_plane++;
330
331 drm_object_attach_property(&plane->base,
332 config->plane_type_property,
333 plane->type);
334
335 if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
336 drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
337 drm_object_attach_property(&plane->base, config->prop_in_fence_fd, -1);
338 drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
339 drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
340 drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
341 drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
342 drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
343 drm_object_attach_property(&plane->base, config->prop_src_x, 0);
344 drm_object_attach_property(&plane->base, config->prop_src_y, 0);
345 drm_object_attach_property(&plane->base, config->prop_src_w, 0);
346 drm_object_attach_property(&plane->base, config->prop_src_h, 0);
347 }
348
349 if (config->allow_fb_modifiers)
350 create_in_format_blob(dev, plane);
351
352 return 0;
353}
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
383 uint32_t possible_crtcs,
384 const struct drm_plane_funcs *funcs,
385 const uint32_t *formats, unsigned int format_count,
386 const uint64_t *format_modifiers,
387 enum drm_plane_type type,
388 const char *name, ...)
389{
390 va_list ap;
391 int ret;
392
393 WARN_ON(!funcs->destroy);
394
395 va_start(ap, name);
396 ret = __drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
397 formats, format_count, format_modifiers,
398 type, name, ap);
399 va_end(ap);
400 return ret;
401}
402EXPORT_SYMBOL(drm_universal_plane_init);
403
404static void drmm_universal_plane_alloc_release(struct drm_device *dev, void *ptr)
405{
406 struct drm_plane *plane = ptr;
407
408 if (WARN_ON(!plane->dev))
409 return;
410
411 drm_plane_cleanup(plane);
412}
413
414void *__drmm_universal_plane_alloc(struct drm_device *dev, size_t size,
415 size_t offset, uint32_t possible_crtcs,
416 const struct drm_plane_funcs *funcs,
417 const uint32_t *formats, unsigned int format_count,
418 const uint64_t *format_modifiers,
419 enum drm_plane_type type,
420 const char *name, ...)
421{
422 void *container;
423 struct drm_plane *plane;
424 va_list ap;
425 int ret;
426
427 if (WARN_ON(!funcs || funcs->destroy))
428 return ERR_PTR(-EINVAL);
429
430 container = drmm_kzalloc(dev, size, GFP_KERNEL);
431 if (!container)
432 return ERR_PTR(-ENOMEM);
433
434 plane = container + offset;
435
436 va_start(ap, name);
437 ret = __drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
438 formats, format_count, format_modifiers,
439 type, name, ap);
440 va_end(ap);
441 if (ret)
442 return ERR_PTR(ret);
443
444 ret = drmm_add_action_or_reset(dev, drmm_universal_plane_alloc_release,
445 plane);
446 if (ret)
447 return ERR_PTR(ret);
448
449 return container;
450}
451EXPORT_SYMBOL(__drmm_universal_plane_alloc);
452
453int drm_plane_register_all(struct drm_device *dev)
454{
455 unsigned int num_planes = 0;
456 unsigned int num_zpos = 0;
457 struct drm_plane *plane;
458 int ret = 0;
459
460 drm_for_each_plane(plane, dev) {
461 if (plane->funcs->late_register)
462 ret = plane->funcs->late_register(plane);
463 if (ret)
464 return ret;
465
466 if (plane->zpos_property)
467 num_zpos++;
468 num_planes++;
469 }
470
471 drm_WARN(dev, num_zpos && num_planes != num_zpos,
472 "Mixing planes with and without zpos property is invalid\n");
473
474 return 0;
475}
476
477void drm_plane_unregister_all(struct drm_device *dev)
478{
479 struct drm_plane *plane;
480
481 drm_for_each_plane(plane, dev) {
482 if (plane->funcs->early_unregister)
483 plane->funcs->early_unregister(plane);
484 }
485}
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
505 uint32_t possible_crtcs,
506 const struct drm_plane_funcs *funcs,
507 const uint32_t *formats, unsigned int format_count,
508 bool is_primary)
509{
510 enum drm_plane_type type;
511
512 type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
513 return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
514 formats, format_count,
515 NULL, type, NULL);
516}
517EXPORT_SYMBOL(drm_plane_init);
518
519
520
521
522
523
524
525
526
527void drm_plane_cleanup(struct drm_plane *plane)
528{
529 struct drm_device *dev = plane->dev;
530
531 drm_modeset_lock_fini(&plane->mutex);
532
533 kfree(plane->format_types);
534 kfree(plane->modifiers);
535 drm_mode_object_unregister(dev, &plane->base);
536
537 BUG_ON(list_empty(&plane->head));
538
539
540
541
542
543
544 list_del(&plane->head);
545 dev->mode_config.num_total_plane--;
546
547 WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
548 if (plane->state && plane->funcs->atomic_destroy_state)
549 plane->funcs->atomic_destroy_state(plane, plane->state);
550
551 kfree(plane->name);
552
553 memset(plane, 0, sizeof(*plane));
554}
555EXPORT_SYMBOL(drm_plane_cleanup);
556
557
558
559
560
561
562
563
564
565struct drm_plane *
566drm_plane_from_index(struct drm_device *dev, int idx)
567{
568 struct drm_plane *plane;
569
570 drm_for_each_plane(plane, dev)
571 if (idx == plane->index)
572 return plane;
573
574 return NULL;
575}
576EXPORT_SYMBOL(drm_plane_from_index);
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593void drm_plane_force_disable(struct drm_plane *plane)
594{
595 int ret;
596
597 if (!plane->fb)
598 return;
599
600 WARN_ON(drm_drv_uses_atomic_modeset(plane->dev));
601
602 plane->old_fb = plane->fb;
603 ret = plane->funcs->disable_plane(plane, NULL);
604 if (ret) {
605 DRM_ERROR("failed to disable plane with busy fb\n");
606 plane->old_fb = NULL;
607 return;
608 }
609
610 drm_framebuffer_put(plane->old_fb);
611 plane->old_fb = NULL;
612 plane->fb = NULL;
613 plane->crtc = NULL;
614}
615EXPORT_SYMBOL(drm_plane_force_disable);
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
631 struct drm_property *property,
632 uint64_t value)
633{
634 int ret = -EINVAL;
635 struct drm_mode_object *obj = &plane->base;
636
637 if (plane->funcs->set_property)
638 ret = plane->funcs->set_property(plane, property, value);
639 if (!ret)
640 drm_object_property_set_value(obj, property, value);
641
642 return ret;
643}
644EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
645
646int drm_mode_getplane_res(struct drm_device *dev, void *data,
647 struct drm_file *file_priv)
648{
649 struct drm_mode_get_plane_res *plane_resp = data;
650 struct drm_plane *plane;
651 uint32_t __user *plane_ptr;
652 int count = 0;
653
654 if (!drm_core_check_feature(dev, DRIVER_MODESET))
655 return -EOPNOTSUPP;
656
657 plane_ptr = u64_to_user_ptr(plane_resp->plane_id_ptr);
658
659
660
661
662
663 drm_for_each_plane(plane, dev) {
664
665
666
667
668 if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
669 !file_priv->universal_planes)
670 continue;
671
672 if (drm_lease_held(file_priv, plane->base.id)) {
673 if (count < plane_resp->count_planes &&
674 put_user(plane->base.id, plane_ptr + count))
675 return -EFAULT;
676 count++;
677 }
678 }
679 plane_resp->count_planes = count;
680
681 return 0;
682}
683
684int drm_mode_getplane(struct drm_device *dev, void *data,
685 struct drm_file *file_priv)
686{
687 struct drm_mode_get_plane *plane_resp = data;
688 struct drm_plane *plane;
689 uint32_t __user *format_ptr;
690
691 if (!drm_core_check_feature(dev, DRIVER_MODESET))
692 return -EOPNOTSUPP;
693
694 plane = drm_plane_find(dev, file_priv, plane_resp->plane_id);
695 if (!plane)
696 return -ENOENT;
697
698 drm_modeset_lock(&plane->mutex, NULL);
699 if (plane->state && plane->state->crtc && drm_lease_held(file_priv, plane->state->crtc->base.id))
700 plane_resp->crtc_id = plane->state->crtc->base.id;
701 else if (!plane->state && plane->crtc && drm_lease_held(file_priv, plane->crtc->base.id))
702 plane_resp->crtc_id = plane->crtc->base.id;
703 else
704 plane_resp->crtc_id = 0;
705
706 if (plane->state && plane->state->fb)
707 plane_resp->fb_id = plane->state->fb->base.id;
708 else if (!plane->state && plane->fb)
709 plane_resp->fb_id = plane->fb->base.id;
710 else
711 plane_resp->fb_id = 0;
712 drm_modeset_unlock(&plane->mutex);
713
714 plane_resp->plane_id = plane->base.id;
715 plane_resp->possible_crtcs = drm_lease_filter_crtcs(file_priv,
716 plane->possible_crtcs);
717
718 plane_resp->gamma_size = 0;
719
720
721
722
723
724 if (plane->format_count &&
725 (plane_resp->count_format_types >= plane->format_count)) {
726 format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;
727 if (copy_to_user(format_ptr,
728 plane->format_types,
729 sizeof(uint32_t) * plane->format_count)) {
730 return -EFAULT;
731 }
732 }
733 plane_resp->count_format_types = plane->format_count;
734
735 return 0;
736}
737
738int drm_plane_check_pixel_format(struct drm_plane *plane,
739 u32 format, u64 modifier)
740{
741 unsigned int i;
742
743 for (i = 0; i < plane->format_count; i++) {
744 if (format == plane->format_types[i])
745 break;
746 }
747 if (i == plane->format_count)
748 return -EINVAL;
749
750 if (plane->funcs->format_mod_supported) {
751 if (!plane->funcs->format_mod_supported(plane, format, modifier))
752 return -EINVAL;
753 } else {
754 if (!plane->modifier_count)
755 return 0;
756
757 for (i = 0; i < plane->modifier_count; i++) {
758 if (modifier == plane->modifiers[i])
759 break;
760 }
761 if (i == plane->modifier_count)
762 return -EINVAL;
763 }
764
765 return 0;
766}
767
768static int __setplane_check(struct drm_plane *plane,
769 struct drm_crtc *crtc,
770 struct drm_framebuffer *fb,
771 int32_t crtc_x, int32_t crtc_y,
772 uint32_t crtc_w, uint32_t crtc_h,
773 uint32_t src_x, uint32_t src_y,
774 uint32_t src_w, uint32_t src_h)
775{
776 int ret;
777
778
779 if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) {
780 DRM_DEBUG_KMS("Invalid crtc for plane\n");
781 return -EINVAL;
782 }
783
784
785 ret = drm_plane_check_pixel_format(plane, fb->format->format,
786 fb->modifier);
787 if (ret) {
788 DRM_DEBUG_KMS("Invalid pixel format %p4cc, modifier 0x%llx\n",
789 &fb->format->format, fb->modifier);
790 return ret;
791 }
792
793
794 if (crtc_w > INT_MAX ||
795 crtc_x > INT_MAX - (int32_t) crtc_w ||
796 crtc_h > INT_MAX ||
797 crtc_y > INT_MAX - (int32_t) crtc_h) {
798 DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
799 crtc_w, crtc_h, crtc_x, crtc_y);
800 return -ERANGE;
801 }
802
803 ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb);
804 if (ret)
805 return ret;
806
807 return 0;
808}
809
810
811
812
813
814
815
816
817
818
819bool drm_any_plane_has_format(struct drm_device *dev,
820 u32 format, u64 modifier)
821{
822 struct drm_plane *plane;
823
824 drm_for_each_plane(plane, dev) {
825 if (drm_plane_check_pixel_format(plane, format, modifier) == 0)
826 return true;
827 }
828
829 return false;
830}
831EXPORT_SYMBOL(drm_any_plane_has_format);
832
833
834
835
836
837
838
839
840
841static int __setplane_internal(struct drm_plane *plane,
842 struct drm_crtc *crtc,
843 struct drm_framebuffer *fb,
844 int32_t crtc_x, int32_t crtc_y,
845 uint32_t crtc_w, uint32_t crtc_h,
846
847 uint32_t src_x, uint32_t src_y,
848 uint32_t src_w, uint32_t src_h,
849 struct drm_modeset_acquire_ctx *ctx)
850{
851 int ret = 0;
852
853 WARN_ON(drm_drv_uses_atomic_modeset(plane->dev));
854
855
856 if (!fb) {
857 plane->old_fb = plane->fb;
858 ret = plane->funcs->disable_plane(plane, ctx);
859 if (!ret) {
860 plane->crtc = NULL;
861 plane->fb = NULL;
862 } else {
863 plane->old_fb = NULL;
864 }
865 goto out;
866 }
867
868 ret = __setplane_check(plane, crtc, fb,
869 crtc_x, crtc_y, crtc_w, crtc_h,
870 src_x, src_y, src_w, src_h);
871 if (ret)
872 goto out;
873
874 plane->old_fb = plane->fb;
875 ret = plane->funcs->update_plane(plane, crtc, fb,
876 crtc_x, crtc_y, crtc_w, crtc_h,
877 src_x, src_y, src_w, src_h, ctx);
878 if (!ret) {
879 plane->crtc = crtc;
880 plane->fb = fb;
881 drm_framebuffer_get(plane->fb);
882 } else {
883 plane->old_fb = NULL;
884 }
885
886out:
887 if (plane->old_fb)
888 drm_framebuffer_put(plane->old_fb);
889 plane->old_fb = NULL;
890
891 return ret;
892}
893
894static int __setplane_atomic(struct drm_plane *plane,
895 struct drm_crtc *crtc,
896 struct drm_framebuffer *fb,
897 int32_t crtc_x, int32_t crtc_y,
898 uint32_t crtc_w, uint32_t crtc_h,
899 uint32_t src_x, uint32_t src_y,
900 uint32_t src_w, uint32_t src_h,
901 struct drm_modeset_acquire_ctx *ctx)
902{
903 int ret;
904
905 WARN_ON(!drm_drv_uses_atomic_modeset(plane->dev));
906
907
908 if (!fb)
909 return plane->funcs->disable_plane(plane, ctx);
910
911
912
913
914
915
916
917
918 ret = __setplane_check(plane, crtc, fb,
919 crtc_x, crtc_y, crtc_w, crtc_h,
920 src_x, src_y, src_w, src_h);
921 if (ret)
922 return ret;
923
924 return plane->funcs->update_plane(plane, crtc, fb,
925 crtc_x, crtc_y, crtc_w, crtc_h,
926 src_x, src_y, src_w, src_h, ctx);
927}
928
929static int setplane_internal(struct drm_plane *plane,
930 struct drm_crtc *crtc,
931 struct drm_framebuffer *fb,
932 int32_t crtc_x, int32_t crtc_y,
933 uint32_t crtc_w, uint32_t crtc_h,
934
935 uint32_t src_x, uint32_t src_y,
936 uint32_t src_w, uint32_t src_h)
937{
938 struct drm_modeset_acquire_ctx ctx;
939 int ret;
940
941 DRM_MODESET_LOCK_ALL_BEGIN(plane->dev, ctx,
942 DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);
943
944 if (drm_drv_uses_atomic_modeset(plane->dev))
945 ret = __setplane_atomic(plane, crtc, fb,
946 crtc_x, crtc_y, crtc_w, crtc_h,
947 src_x, src_y, src_w, src_h, &ctx);
948 else
949 ret = __setplane_internal(plane, crtc, fb,
950 crtc_x, crtc_y, crtc_w, crtc_h,
951 src_x, src_y, src_w, src_h, &ctx);
952
953 DRM_MODESET_LOCK_ALL_END(plane->dev, ctx, ret);
954
955 return ret;
956}
957
958int drm_mode_setplane(struct drm_device *dev, void *data,
959 struct drm_file *file_priv)
960{
961 struct drm_mode_set_plane *plane_req = data;
962 struct drm_plane *plane;
963 struct drm_crtc *crtc = NULL;
964 struct drm_framebuffer *fb = NULL;
965 int ret;
966
967 if (!drm_core_check_feature(dev, DRIVER_MODESET))
968 return -EOPNOTSUPP;
969
970
971
972
973
974 plane = drm_plane_find(dev, file_priv, plane_req->plane_id);
975 if (!plane) {
976 DRM_DEBUG_KMS("Unknown plane ID %d\n",
977 plane_req->plane_id);
978 return -ENOENT;
979 }
980
981 if (plane_req->fb_id) {
982 fb = drm_framebuffer_lookup(dev, file_priv, plane_req->fb_id);
983 if (!fb) {
984 DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
985 plane_req->fb_id);
986 return -ENOENT;
987 }
988
989 crtc = drm_crtc_find(dev, file_priv, plane_req->crtc_id);
990 if (!crtc) {
991 drm_framebuffer_put(fb);
992 DRM_DEBUG_KMS("Unknown crtc ID %d\n",
993 plane_req->crtc_id);
994 return -ENOENT;
995 }
996 }
997
998 ret = setplane_internal(plane, crtc, fb,
999 plane_req->crtc_x, plane_req->crtc_y,
1000 plane_req->crtc_w, plane_req->crtc_h,
1001 plane_req->src_x, plane_req->src_y,
1002 plane_req->src_w, plane_req->src_h);
1003
1004 if (fb)
1005 drm_framebuffer_put(fb);
1006
1007 return ret;
1008}
1009
1010static int drm_mode_cursor_universal(struct drm_crtc *crtc,
1011 struct drm_mode_cursor2 *req,
1012 struct drm_file *file_priv,
1013 struct drm_modeset_acquire_ctx *ctx)
1014{
1015 struct drm_device *dev = crtc->dev;
1016 struct drm_plane *plane = crtc->cursor;
1017 struct drm_framebuffer *fb = NULL;
1018 struct drm_mode_fb_cmd2 fbreq = {
1019 .width = req->width,
1020 .height = req->height,
1021 .pixel_format = DRM_FORMAT_ARGB8888,
1022 .pitches = { req->width * 4 },
1023 .handles = { req->handle },
1024 };
1025 int32_t crtc_x, crtc_y;
1026 uint32_t crtc_w = 0, crtc_h = 0;
1027 uint32_t src_w = 0, src_h = 0;
1028 int ret = 0;
1029
1030 BUG_ON(!plane);
1031 WARN_ON(plane->crtc != crtc && plane->crtc != NULL);
1032
1033
1034
1035
1036
1037
1038 if (req->flags & DRM_MODE_CURSOR_BO) {
1039 if (req->handle) {
1040 fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv);
1041 if (IS_ERR(fb)) {
1042 DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
1043 return PTR_ERR(fb);
1044 }
1045
1046 fb->hot_x = req->hot_x;
1047 fb->hot_y = req->hot_y;
1048 } else {
1049 fb = NULL;
1050 }
1051 } else {
1052 if (plane->state)
1053 fb = plane->state->fb;
1054 else
1055 fb = plane->fb;
1056
1057 if (fb)
1058 drm_framebuffer_get(fb);
1059 }
1060
1061 if (req->flags & DRM_MODE_CURSOR_MOVE) {
1062 crtc_x = req->x;
1063 crtc_y = req->y;
1064 } else {
1065 crtc_x = crtc->cursor_x;
1066 crtc_y = crtc->cursor_y;
1067 }
1068
1069 if (fb) {
1070 crtc_w = fb->width;
1071 crtc_h = fb->height;
1072 src_w = fb->width << 16;
1073 src_h = fb->height << 16;
1074 }
1075
1076 if (drm_drv_uses_atomic_modeset(dev))
1077 ret = __setplane_atomic(plane, crtc, fb,
1078 crtc_x, crtc_y, crtc_w, crtc_h,
1079 0, 0, src_w, src_h, ctx);
1080 else
1081 ret = __setplane_internal(plane, crtc, fb,
1082 crtc_x, crtc_y, crtc_w, crtc_h,
1083 0, 0, src_w, src_h, ctx);
1084
1085 if (fb)
1086 drm_framebuffer_put(fb);
1087
1088
1089 if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) {
1090 crtc->cursor_x = req->x;
1091 crtc->cursor_y = req->y;
1092 }
1093
1094 return ret;
1095}
1096
1097static int drm_mode_cursor_common(struct drm_device *dev,
1098 struct drm_mode_cursor2 *req,
1099 struct drm_file *file_priv)
1100{
1101 struct drm_crtc *crtc;
1102 struct drm_modeset_acquire_ctx ctx;
1103 int ret = 0;
1104
1105 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1106 return -EOPNOTSUPP;
1107
1108 if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
1109 return -EINVAL;
1110
1111 crtc = drm_crtc_find(dev, file_priv, req->crtc_id);
1112 if (!crtc) {
1113 DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
1114 return -ENOENT;
1115 }
1116
1117 drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
1118retry:
1119 ret = drm_modeset_lock(&crtc->mutex, &ctx);
1120 if (ret)
1121 goto out;
1122
1123
1124
1125
1126 if (crtc->cursor) {
1127 ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx);
1128 if (ret)
1129 goto out;
1130
1131 if (!drm_lease_held(file_priv, crtc->cursor->base.id)) {
1132 ret = -EACCES;
1133 goto out;
1134 }
1135
1136 ret = drm_mode_cursor_universal(crtc, req, file_priv, &ctx);
1137 goto out;
1138 }
1139
1140 if (req->flags & DRM_MODE_CURSOR_BO) {
1141 if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
1142 ret = -ENXIO;
1143 goto out;
1144 }
1145
1146 if (crtc->funcs->cursor_set2)
1147 ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle,
1148 req->width, req->height, req->hot_x, req->hot_y);
1149 else
1150 ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
1151 req->width, req->height);
1152 }
1153
1154 if (req->flags & DRM_MODE_CURSOR_MOVE) {
1155 if (crtc->funcs->cursor_move) {
1156 ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
1157 } else {
1158 ret = -EFAULT;
1159 goto out;
1160 }
1161 }
1162out:
1163 if (ret == -EDEADLK) {
1164 ret = drm_modeset_backoff(&ctx);
1165 if (!ret)
1166 goto retry;
1167 }
1168
1169 drm_modeset_drop_locks(&ctx);
1170 drm_modeset_acquire_fini(&ctx);
1171
1172 return ret;
1173
1174}
1175
1176
1177int drm_mode_cursor_ioctl(struct drm_device *dev,
1178 void *data, struct drm_file *file_priv)
1179{
1180 struct drm_mode_cursor *req = data;
1181 struct drm_mode_cursor2 new_req;
1182
1183 memcpy(&new_req, req, sizeof(struct drm_mode_cursor));
1184 new_req.hot_x = new_req.hot_y = 0;
1185
1186 return drm_mode_cursor_common(dev, &new_req, file_priv);
1187}
1188
1189
1190
1191
1192
1193
1194int drm_mode_cursor2_ioctl(struct drm_device *dev,
1195 void *data, struct drm_file *file_priv)
1196{
1197 struct drm_mode_cursor2 *req = data;
1198
1199 return drm_mode_cursor_common(dev, req, file_priv);
1200}
1201
1202int drm_mode_page_flip_ioctl(struct drm_device *dev,
1203 void *data, struct drm_file *file_priv)
1204{
1205 struct drm_mode_crtc_page_flip_target *page_flip = data;
1206 struct drm_crtc *crtc;
1207 struct drm_plane *plane;
1208 struct drm_framebuffer *fb = NULL, *old_fb;
1209 struct drm_pending_vblank_event *e = NULL;
1210 u32 target_vblank = page_flip->sequence;
1211 struct drm_modeset_acquire_ctx ctx;
1212 int ret = -EINVAL;
1213
1214 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1215 return -EOPNOTSUPP;
1216
1217 if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS)
1218 return -EINVAL;
1219
1220 if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET))
1221 return -EINVAL;
1222
1223
1224
1225
1226 if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET)
1227 return -EINVAL;
1228
1229 if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
1230 return -EINVAL;
1231
1232 crtc = drm_crtc_find(dev, file_priv, page_flip->crtc_id);
1233 if (!crtc)
1234 return -ENOENT;
1235
1236 plane = crtc->primary;
1237
1238 if (!drm_lease_held(file_priv, plane->base.id))
1239 return -EACCES;
1240
1241 if (crtc->funcs->page_flip_target) {
1242 u32 current_vblank;
1243 int r;
1244
1245 r = drm_crtc_vblank_get(crtc);
1246 if (r)
1247 return r;
1248
1249 current_vblank = (u32)drm_crtc_vblank_count(crtc);
1250
1251 switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) {
1252 case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE:
1253 if ((int)(target_vblank - current_vblank) > 1) {
1254 DRM_DEBUG("Invalid absolute flip target %u, "
1255 "must be <= %u\n", target_vblank,
1256 current_vblank + 1);
1257 drm_crtc_vblank_put(crtc);
1258 return -EINVAL;
1259 }
1260 break;
1261 case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE:
1262 if (target_vblank != 0 && target_vblank != 1) {
1263 DRM_DEBUG("Invalid relative flip target %u, "
1264 "must be 0 or 1\n", target_vblank);
1265 drm_crtc_vblank_put(crtc);
1266 return -EINVAL;
1267 }
1268 target_vblank += current_vblank;
1269 break;
1270 default:
1271 target_vblank = current_vblank +
1272 !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC);
1273 break;
1274 }
1275 } else if (crtc->funcs->page_flip == NULL ||
1276 (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) {
1277 return -EINVAL;
1278 }
1279
1280 drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
1281retry:
1282 ret = drm_modeset_lock(&crtc->mutex, &ctx);
1283 if (ret)
1284 goto out;
1285 ret = drm_modeset_lock(&plane->mutex, &ctx);
1286 if (ret)
1287 goto out;
1288
1289 if (plane->state)
1290 old_fb = plane->state->fb;
1291 else
1292 old_fb = plane->fb;
1293
1294 if (old_fb == NULL) {
1295
1296
1297
1298
1299 ret = -EBUSY;
1300 goto out;
1301 }
1302
1303 fb = drm_framebuffer_lookup(dev, file_priv, page_flip->fb_id);
1304 if (!fb) {
1305 ret = -ENOENT;
1306 goto out;
1307 }
1308
1309 if (plane->state) {
1310 const struct drm_plane_state *state = plane->state;
1311
1312 ret = drm_framebuffer_check_src_coords(state->src_x,
1313 state->src_y,
1314 state->src_w,
1315 state->src_h,
1316 fb);
1317 } else {
1318 ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y,
1319 &crtc->mode, fb);
1320 }
1321 if (ret)
1322 goto out;
1323
1324
1325
1326
1327
1328
1329
1330
1331 if (old_fb->format->format != fb->format->format) {
1332 DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
1333 ret = -EINVAL;
1334 goto out;
1335 }
1336
1337 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
1338 e = kzalloc(sizeof *e, GFP_KERNEL);
1339 if (!e) {
1340 ret = -ENOMEM;
1341 goto out;
1342 }
1343
1344 e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
1345 e->event.base.length = sizeof(e->event);
1346 e->event.vbl.user_data = page_flip->user_data;
1347 e->event.vbl.crtc_id = crtc->base.id;
1348
1349 ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
1350 if (ret) {
1351 kfree(e);
1352 e = NULL;
1353 goto out;
1354 }
1355 }
1356
1357 plane->old_fb = plane->fb;
1358 if (crtc->funcs->page_flip_target)
1359 ret = crtc->funcs->page_flip_target(crtc, fb, e,
1360 page_flip->flags,
1361 target_vblank,
1362 &ctx);
1363 else
1364 ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags,
1365 &ctx);
1366 if (ret) {
1367 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT)
1368 drm_event_cancel_free(dev, &e->base);
1369
1370 plane->old_fb = NULL;
1371 } else {
1372 if (!plane->state) {
1373 plane->fb = fb;
1374 drm_framebuffer_get(fb);
1375 }
1376 }
1377
1378out:
1379 if (fb)
1380 drm_framebuffer_put(fb);
1381 if (plane->old_fb)
1382 drm_framebuffer_put(plane->old_fb);
1383 plane->old_fb = NULL;
1384
1385 if (ret == -EDEADLK) {
1386 ret = drm_modeset_backoff(&ctx);
1387 if (!ret)
1388 goto retry;
1389 }
1390
1391 drm_modeset_drop_locks(&ctx);
1392 drm_modeset_acquire_fini(&ctx);
1393
1394 if (ret && crtc->funcs->page_flip_target)
1395 drm_crtc_vblank_put(crtc);
1396
1397 return ret;
1398}
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444void drm_plane_enable_fb_damage_clips(struct drm_plane *plane)
1445{
1446 struct drm_device *dev = plane->dev;
1447 struct drm_mode_config *config = &dev->mode_config;
1448
1449 drm_object_attach_property(&plane->base, config->prop_fb_damage_clips,
1450 0);
1451}
1452EXPORT_SYMBOL(drm_plane_enable_fb_damage_clips);
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463unsigned int
1464drm_plane_get_damage_clips_count(const struct drm_plane_state *state)
1465{
1466 return (state && state->fb_damage_clips) ?
1467 state->fb_damage_clips->length/sizeof(struct drm_mode_rect) : 0;
1468}
1469EXPORT_SYMBOL(drm_plane_get_damage_clips_count);
1470
1471struct drm_mode_rect *
1472__drm_plane_get_damage_clips(const struct drm_plane_state *state)
1473{
1474 return (struct drm_mode_rect *)((state && state->fb_damage_clips) ?
1475 state->fb_damage_clips->data : NULL);
1476}
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489struct drm_mode_rect *
1490drm_plane_get_damage_clips(const struct drm_plane_state *state)
1491{
1492 struct drm_device *dev = state->plane->dev;
1493 struct drm_mode_config *config = &dev->mode_config;
1494
1495
1496 if (!drm_mode_obj_find_prop_id(&state->plane->base,
1497 config->prop_fb_damage_clips->base.id))
1498 drm_warn_once(dev, "drm_plane_enable_fb_damage_clips() not called\n");
1499
1500 return __drm_plane_get_damage_clips(state);
1501}
1502EXPORT_SYMBOL(drm_plane_get_damage_clips);
1503
1504struct drm_property *
1505drm_create_scaling_filter_prop(struct drm_device *dev,
1506 unsigned int supported_filters)
1507{
1508 struct drm_property *prop;
1509 static const struct drm_prop_enum_list props[] = {
1510 { DRM_SCALING_FILTER_DEFAULT, "Default" },
1511 { DRM_SCALING_FILTER_NEAREST_NEIGHBOR, "Nearest Neighbor" },
1512 };
1513 unsigned int valid_mode_mask = BIT(DRM_SCALING_FILTER_DEFAULT) |
1514 BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR);
1515 int i;
1516
1517 if (WARN_ON((supported_filters & ~valid_mode_mask) ||
1518 ((supported_filters & BIT(DRM_SCALING_FILTER_DEFAULT)) == 0)))
1519 return ERR_PTR(-EINVAL);
1520
1521 prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
1522 "SCALING_FILTER",
1523 hweight32(supported_filters));
1524 if (!prop)
1525 return ERR_PTR(-ENOMEM);
1526
1527 for (i = 0; i < ARRAY_SIZE(props); i++) {
1528 int ret;
1529
1530 if (!(BIT(props[i].type) & supported_filters))
1531 continue;
1532
1533 ret = drm_property_add_enum(prop, props[i].type,
1534 props[i].name);
1535
1536 if (ret) {
1537 drm_property_destroy(dev, prop);
1538
1539 return ERR_PTR(ret);
1540 }
1541 }
1542
1543 return prop;
1544}
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560int drm_plane_create_scaling_filter_property(struct drm_plane *plane,
1561 unsigned int supported_filters)
1562{
1563 struct drm_property *prop =
1564 drm_create_scaling_filter_prop(plane->dev, supported_filters);
1565
1566 if (IS_ERR(prop))
1567 return PTR_ERR(prop);
1568
1569 drm_object_attach_property(&plane->base, prop,
1570 DRM_SCALING_FILTER_DEFAULT);
1571 plane->scaling_filter_property = prop;
1572
1573 return 0;
1574}
1575EXPORT_SYMBOL(drm_plane_create_scaling_filter_property);
1576