0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 #include <linux/slab.h>
0024 #include <linux/uaccess.h>
0025
0026 #include <drm/drm_plane.h>
0027 #include <drm/drm_drv.h>
0028 #include <drm/drm_print.h>
0029 #include <drm/drm_framebuffer.h>
0030 #include <drm/drm_file.h>
0031 #include <drm/drm_crtc.h>
0032 #include <drm/drm_fourcc.h>
0033 #include <drm/drm_managed.h>
0034 #include <drm/drm_vblank.h>
0035
0036 #include "drm_crtc_internal.h"
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140 static unsigned int drm_num_planes(struct drm_device *dev)
0141 {
0142 unsigned int num = 0;
0143 struct drm_plane *tmp;
0144
0145 drm_for_each_plane(tmp, dev) {
0146 num++;
0147 }
0148
0149 return num;
0150 }
0151
0152 static inline u32 *
0153 formats_ptr(struct drm_format_modifier_blob *blob)
0154 {
0155 return (u32 *)(((char *)blob) + blob->formats_offset);
0156 }
0157
0158 static inline struct drm_format_modifier *
0159 modifiers_ptr(struct drm_format_modifier_blob *blob)
0160 {
0161 return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
0162 }
0163
0164 static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane)
0165 {
0166 const struct drm_mode_config *config = &dev->mode_config;
0167 struct drm_property_blob *blob;
0168 struct drm_format_modifier *mod;
0169 size_t blob_size, formats_size, modifiers_size;
0170 struct drm_format_modifier_blob *blob_data;
0171 unsigned int i, j;
0172
0173 formats_size = sizeof(__u32) * plane->format_count;
0174 if (WARN_ON(!formats_size)) {
0175
0176 return 0;
0177 }
0178
0179 modifiers_size =
0180 sizeof(struct drm_format_modifier) * plane->modifier_count;
0181
0182 blob_size = sizeof(struct drm_format_modifier_blob);
0183
0184
0185
0186 BUILD_BUG_ON(sizeof(struct drm_format_modifier_blob) % 8);
0187 blob_size += ALIGN(formats_size, 8);
0188 blob_size += modifiers_size;
0189
0190 blob = drm_property_create_blob(dev, blob_size, NULL);
0191 if (IS_ERR(blob))
0192 return -1;
0193
0194 blob_data = blob->data;
0195 blob_data->version = FORMAT_BLOB_CURRENT;
0196 blob_data->count_formats = plane->format_count;
0197 blob_data->formats_offset = sizeof(struct drm_format_modifier_blob);
0198 blob_data->count_modifiers = plane->modifier_count;
0199
0200 blob_data->modifiers_offset =
0201 ALIGN(blob_data->formats_offset + formats_size, 8);
0202
0203 memcpy(formats_ptr(blob_data), plane->format_types, formats_size);
0204
0205 mod = modifiers_ptr(blob_data);
0206 for (i = 0; i < plane->modifier_count; i++) {
0207 for (j = 0; j < plane->format_count; j++) {
0208 if (!plane->funcs->format_mod_supported ||
0209 plane->funcs->format_mod_supported(plane,
0210 plane->format_types[j],
0211 plane->modifiers[i])) {
0212 mod->formats |= 1ULL << j;
0213 }
0214 }
0215
0216 mod->modifier = plane->modifiers[i];
0217 mod->offset = 0;
0218 mod->pad = 0;
0219 mod++;
0220 }
0221
0222 drm_object_attach_property(&plane->base, config->modifiers_property,
0223 blob->base.id);
0224
0225 return 0;
0226 }
0227
0228 __printf(9, 0)
0229 static int __drm_universal_plane_init(struct drm_device *dev,
0230 struct drm_plane *plane,
0231 uint32_t possible_crtcs,
0232 const struct drm_plane_funcs *funcs,
0233 const uint32_t *formats,
0234 unsigned int format_count,
0235 const uint64_t *format_modifiers,
0236 enum drm_plane_type type,
0237 const char *name, va_list ap)
0238 {
0239 struct drm_mode_config *config = &dev->mode_config;
0240 static const uint64_t default_modifiers[] = {
0241 DRM_FORMAT_MOD_LINEAR,
0242 };
0243 unsigned int format_modifier_count = 0;
0244 int ret;
0245
0246
0247 if (WARN_ON(config->num_total_plane >= 32))
0248 return -EINVAL;
0249
0250
0251
0252
0253
0254 if (WARN_ON(format_count > 64))
0255 return -EINVAL;
0256
0257 WARN_ON(drm_drv_uses_atomic_modeset(dev) &&
0258 (!funcs->atomic_destroy_state ||
0259 !funcs->atomic_duplicate_state));
0260
0261 ret = drm_mode_object_add(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
0262 if (ret)
0263 return ret;
0264
0265 drm_modeset_lock_init(&plane->mutex);
0266
0267 plane->base.properties = &plane->properties;
0268 plane->dev = dev;
0269 plane->funcs = funcs;
0270 plane->format_types = kmalloc_array(format_count, sizeof(uint32_t),
0271 GFP_KERNEL);
0272 if (!plane->format_types) {
0273 DRM_DEBUG_KMS("out of memory when allocating plane\n");
0274 drm_mode_object_unregister(dev, &plane->base);
0275 return -ENOMEM;
0276 }
0277
0278 if (format_modifiers) {
0279 const uint64_t *temp_modifiers = format_modifiers;
0280
0281 while (*temp_modifiers++ != DRM_FORMAT_MOD_INVALID)
0282 format_modifier_count++;
0283 } else {
0284 if (!dev->mode_config.fb_modifiers_not_supported) {
0285 format_modifiers = default_modifiers;
0286 format_modifier_count = ARRAY_SIZE(default_modifiers);
0287 }
0288 }
0289
0290
0291 drm_WARN_ON(dev, config->fb_modifiers_not_supported &&
0292 format_modifier_count);
0293
0294 plane->modifier_count = format_modifier_count;
0295 plane->modifiers = kmalloc_array(format_modifier_count,
0296 sizeof(format_modifiers[0]),
0297 GFP_KERNEL);
0298
0299 if (format_modifier_count && !plane->modifiers) {
0300 DRM_DEBUG_KMS("out of memory when allocating plane\n");
0301 kfree(plane->format_types);
0302 drm_mode_object_unregister(dev, &plane->base);
0303 return -ENOMEM;
0304 }
0305
0306 if (name) {
0307 plane->name = kvasprintf(GFP_KERNEL, name, ap);
0308 } else {
0309 plane->name = kasprintf(GFP_KERNEL, "plane-%d",
0310 drm_num_planes(dev));
0311 }
0312 if (!plane->name) {
0313 kfree(plane->format_types);
0314 kfree(plane->modifiers);
0315 drm_mode_object_unregister(dev, &plane->base);
0316 return -ENOMEM;
0317 }
0318
0319 memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
0320 plane->format_count = format_count;
0321 memcpy(plane->modifiers, format_modifiers,
0322 format_modifier_count * sizeof(format_modifiers[0]));
0323 plane->possible_crtcs = possible_crtcs;
0324 plane->type = type;
0325
0326 list_add_tail(&plane->head, &config->plane_list);
0327 plane->index = config->num_total_plane++;
0328
0329 drm_object_attach_property(&plane->base,
0330 config->plane_type_property,
0331 plane->type);
0332
0333 if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
0334 drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
0335 drm_object_attach_property(&plane->base, config->prop_in_fence_fd, -1);
0336 drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
0337 drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
0338 drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
0339 drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
0340 drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
0341 drm_object_attach_property(&plane->base, config->prop_src_x, 0);
0342 drm_object_attach_property(&plane->base, config->prop_src_y, 0);
0343 drm_object_attach_property(&plane->base, config->prop_src_w, 0);
0344 drm_object_attach_property(&plane->base, config->prop_src_h, 0);
0345 }
0346
0347 if (format_modifier_count)
0348 create_in_format_blob(dev, plane);
0349
0350 return 0;
0351 }
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380 int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
0381 uint32_t possible_crtcs,
0382 const struct drm_plane_funcs *funcs,
0383 const uint32_t *formats, unsigned int format_count,
0384 const uint64_t *format_modifiers,
0385 enum drm_plane_type type,
0386 const char *name, ...)
0387 {
0388 va_list ap;
0389 int ret;
0390
0391 WARN_ON(!funcs->destroy);
0392
0393 va_start(ap, name);
0394 ret = __drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
0395 formats, format_count, format_modifiers,
0396 type, name, ap);
0397 va_end(ap);
0398 return ret;
0399 }
0400 EXPORT_SYMBOL(drm_universal_plane_init);
0401
0402 static void drmm_universal_plane_alloc_release(struct drm_device *dev, void *ptr)
0403 {
0404 struct drm_plane *plane = ptr;
0405
0406 if (WARN_ON(!plane->dev))
0407 return;
0408
0409 drm_plane_cleanup(plane);
0410 }
0411
0412 void *__drmm_universal_plane_alloc(struct drm_device *dev, size_t size,
0413 size_t offset, uint32_t possible_crtcs,
0414 const struct drm_plane_funcs *funcs,
0415 const uint32_t *formats, unsigned int format_count,
0416 const uint64_t *format_modifiers,
0417 enum drm_plane_type type,
0418 const char *name, ...)
0419 {
0420 void *container;
0421 struct drm_plane *plane;
0422 va_list ap;
0423 int ret;
0424
0425 if (WARN_ON(!funcs || funcs->destroy))
0426 return ERR_PTR(-EINVAL);
0427
0428 container = drmm_kzalloc(dev, size, GFP_KERNEL);
0429 if (!container)
0430 return ERR_PTR(-ENOMEM);
0431
0432 plane = container + offset;
0433
0434 va_start(ap, name);
0435 ret = __drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
0436 formats, format_count, format_modifiers,
0437 type, name, ap);
0438 va_end(ap);
0439 if (ret)
0440 return ERR_PTR(ret);
0441
0442 ret = drmm_add_action_or_reset(dev, drmm_universal_plane_alloc_release,
0443 plane);
0444 if (ret)
0445 return ERR_PTR(ret);
0446
0447 return container;
0448 }
0449 EXPORT_SYMBOL(__drmm_universal_plane_alloc);
0450
0451 int drm_plane_register_all(struct drm_device *dev)
0452 {
0453 unsigned int num_planes = 0;
0454 unsigned int num_zpos = 0;
0455 struct drm_plane *plane;
0456 int ret = 0;
0457
0458 drm_for_each_plane(plane, dev) {
0459 if (plane->funcs->late_register)
0460 ret = plane->funcs->late_register(plane);
0461 if (ret)
0462 return ret;
0463
0464 if (plane->zpos_property)
0465 num_zpos++;
0466 num_planes++;
0467 }
0468
0469 drm_WARN(dev, num_zpos && num_planes != num_zpos,
0470 "Mixing planes with and without zpos property is invalid\n");
0471
0472 return 0;
0473 }
0474
0475 void drm_plane_unregister_all(struct drm_device *dev)
0476 {
0477 struct drm_plane *plane;
0478
0479 drm_for_each_plane(plane, dev) {
0480 if (plane->funcs->early_unregister)
0481 plane->funcs->early_unregister(plane);
0482 }
0483 }
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502 int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
0503 uint32_t possible_crtcs,
0504 const struct drm_plane_funcs *funcs,
0505 const uint32_t *formats, unsigned int format_count,
0506 bool is_primary)
0507 {
0508 enum drm_plane_type type;
0509
0510 type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
0511 return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
0512 formats, format_count,
0513 NULL, type, NULL);
0514 }
0515 EXPORT_SYMBOL(drm_plane_init);
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525 void drm_plane_cleanup(struct drm_plane *plane)
0526 {
0527 struct drm_device *dev = plane->dev;
0528
0529 drm_modeset_lock_fini(&plane->mutex);
0530
0531 kfree(plane->format_types);
0532 kfree(plane->modifiers);
0533 drm_mode_object_unregister(dev, &plane->base);
0534
0535 BUG_ON(list_empty(&plane->head));
0536
0537
0538
0539
0540
0541
0542 list_del(&plane->head);
0543 dev->mode_config.num_total_plane--;
0544
0545 WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
0546 if (plane->state && plane->funcs->atomic_destroy_state)
0547 plane->funcs->atomic_destroy_state(plane, plane->state);
0548
0549 kfree(plane->name);
0550
0551 memset(plane, 0, sizeof(*plane));
0552 }
0553 EXPORT_SYMBOL(drm_plane_cleanup);
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563 struct drm_plane *
0564 drm_plane_from_index(struct drm_device *dev, int idx)
0565 {
0566 struct drm_plane *plane;
0567
0568 drm_for_each_plane(plane, dev)
0569 if (idx == plane->index)
0570 return plane;
0571
0572 return NULL;
0573 }
0574 EXPORT_SYMBOL(drm_plane_from_index);
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591 void drm_plane_force_disable(struct drm_plane *plane)
0592 {
0593 int ret;
0594
0595 if (!plane->fb)
0596 return;
0597
0598 WARN_ON(drm_drv_uses_atomic_modeset(plane->dev));
0599
0600 plane->old_fb = plane->fb;
0601 ret = plane->funcs->disable_plane(plane, NULL);
0602 if (ret) {
0603 DRM_ERROR("failed to disable plane with busy fb\n");
0604 plane->old_fb = NULL;
0605 return;
0606 }
0607
0608 drm_framebuffer_put(plane->old_fb);
0609 plane->old_fb = NULL;
0610 plane->fb = NULL;
0611 plane->crtc = NULL;
0612 }
0613 EXPORT_SYMBOL(drm_plane_force_disable);
0614
0615
0616
0617
0618
0619
0620
0621
0622
0623
0624
0625
0626
0627
0628 int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
0629 struct drm_property *property,
0630 uint64_t value)
0631 {
0632 int ret = -EINVAL;
0633 struct drm_mode_object *obj = &plane->base;
0634
0635 if (plane->funcs->set_property)
0636 ret = plane->funcs->set_property(plane, property, value);
0637 if (!ret)
0638 drm_object_property_set_value(obj, property, value);
0639
0640 return ret;
0641 }
0642 EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
0643
0644 int drm_mode_getplane_res(struct drm_device *dev, void *data,
0645 struct drm_file *file_priv)
0646 {
0647 struct drm_mode_get_plane_res *plane_resp = data;
0648 struct drm_plane *plane;
0649 uint32_t __user *plane_ptr;
0650 int count = 0;
0651
0652 if (!drm_core_check_feature(dev, DRIVER_MODESET))
0653 return -EOPNOTSUPP;
0654
0655 plane_ptr = u64_to_user_ptr(plane_resp->plane_id_ptr);
0656
0657
0658
0659
0660
0661 drm_for_each_plane(plane, dev) {
0662
0663
0664
0665
0666 if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
0667 !file_priv->universal_planes)
0668 continue;
0669
0670 if (drm_lease_held(file_priv, plane->base.id)) {
0671 if (count < plane_resp->count_planes &&
0672 put_user(plane->base.id, plane_ptr + count))
0673 return -EFAULT;
0674 count++;
0675 }
0676 }
0677 plane_resp->count_planes = count;
0678
0679 return 0;
0680 }
0681
0682 int drm_mode_getplane(struct drm_device *dev, void *data,
0683 struct drm_file *file_priv)
0684 {
0685 struct drm_mode_get_plane *plane_resp = data;
0686 struct drm_plane *plane;
0687 uint32_t __user *format_ptr;
0688
0689 if (!drm_core_check_feature(dev, DRIVER_MODESET))
0690 return -EOPNOTSUPP;
0691
0692 plane = drm_plane_find(dev, file_priv, plane_resp->plane_id);
0693 if (!plane)
0694 return -ENOENT;
0695
0696 drm_modeset_lock(&plane->mutex, NULL);
0697 if (plane->state && plane->state->crtc && drm_lease_held(file_priv, plane->state->crtc->base.id))
0698 plane_resp->crtc_id = plane->state->crtc->base.id;
0699 else if (!plane->state && plane->crtc && drm_lease_held(file_priv, plane->crtc->base.id))
0700 plane_resp->crtc_id = plane->crtc->base.id;
0701 else
0702 plane_resp->crtc_id = 0;
0703
0704 if (plane->state && plane->state->fb)
0705 plane_resp->fb_id = plane->state->fb->base.id;
0706 else if (!plane->state && plane->fb)
0707 plane_resp->fb_id = plane->fb->base.id;
0708 else
0709 plane_resp->fb_id = 0;
0710 drm_modeset_unlock(&plane->mutex);
0711
0712 plane_resp->plane_id = plane->base.id;
0713 plane_resp->possible_crtcs = drm_lease_filter_crtcs(file_priv,
0714 plane->possible_crtcs);
0715
0716 plane_resp->gamma_size = 0;
0717
0718
0719
0720
0721
0722 if (plane->format_count &&
0723 (plane_resp->count_format_types >= plane->format_count)) {
0724 format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;
0725 if (copy_to_user(format_ptr,
0726 plane->format_types,
0727 sizeof(uint32_t) * plane->format_count)) {
0728 return -EFAULT;
0729 }
0730 }
0731 plane_resp->count_format_types = plane->format_count;
0732
0733 return 0;
0734 }
0735
0736 int drm_plane_check_pixel_format(struct drm_plane *plane,
0737 u32 format, u64 modifier)
0738 {
0739 unsigned int i;
0740
0741 for (i = 0; i < plane->format_count; i++) {
0742 if (format == plane->format_types[i])
0743 break;
0744 }
0745 if (i == plane->format_count)
0746 return -EINVAL;
0747
0748 if (plane->funcs->format_mod_supported) {
0749 if (!plane->funcs->format_mod_supported(plane, format, modifier))
0750 return -EINVAL;
0751 } else {
0752 if (!plane->modifier_count)
0753 return 0;
0754
0755 for (i = 0; i < plane->modifier_count; i++) {
0756 if (modifier == plane->modifiers[i])
0757 break;
0758 }
0759 if (i == plane->modifier_count)
0760 return -EINVAL;
0761 }
0762
0763 return 0;
0764 }
0765
0766 static int __setplane_check(struct drm_plane *plane,
0767 struct drm_crtc *crtc,
0768 struct drm_framebuffer *fb,
0769 int32_t crtc_x, int32_t crtc_y,
0770 uint32_t crtc_w, uint32_t crtc_h,
0771 uint32_t src_x, uint32_t src_y,
0772 uint32_t src_w, uint32_t src_h)
0773 {
0774 int ret;
0775
0776
0777 if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) {
0778 DRM_DEBUG_KMS("Invalid crtc for plane\n");
0779 return -EINVAL;
0780 }
0781
0782
0783 ret = drm_plane_check_pixel_format(plane, fb->format->format,
0784 fb->modifier);
0785 if (ret) {
0786 DRM_DEBUG_KMS("Invalid pixel format %p4cc, modifier 0x%llx\n",
0787 &fb->format->format, fb->modifier);
0788 return ret;
0789 }
0790
0791
0792 if (crtc_w > INT_MAX ||
0793 crtc_x > INT_MAX - (int32_t) crtc_w ||
0794 crtc_h > INT_MAX ||
0795 crtc_y > INT_MAX - (int32_t) crtc_h) {
0796 DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
0797 crtc_w, crtc_h, crtc_x, crtc_y);
0798 return -ERANGE;
0799 }
0800
0801 ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb);
0802 if (ret)
0803 return ret;
0804
0805 return 0;
0806 }
0807
0808
0809
0810
0811
0812
0813
0814
0815
0816
0817 bool drm_any_plane_has_format(struct drm_device *dev,
0818 u32 format, u64 modifier)
0819 {
0820 struct drm_plane *plane;
0821
0822 drm_for_each_plane(plane, dev) {
0823 if (drm_plane_check_pixel_format(plane, format, modifier) == 0)
0824 return true;
0825 }
0826
0827 return false;
0828 }
0829 EXPORT_SYMBOL(drm_any_plane_has_format);
0830
0831
0832
0833
0834
0835
0836
0837
0838
0839 static int __setplane_internal(struct drm_plane *plane,
0840 struct drm_crtc *crtc,
0841 struct drm_framebuffer *fb,
0842 int32_t crtc_x, int32_t crtc_y,
0843 uint32_t crtc_w, uint32_t crtc_h,
0844
0845 uint32_t src_x, uint32_t src_y,
0846 uint32_t src_w, uint32_t src_h,
0847 struct drm_modeset_acquire_ctx *ctx)
0848 {
0849 int ret = 0;
0850
0851 WARN_ON(drm_drv_uses_atomic_modeset(plane->dev));
0852
0853
0854 if (!fb) {
0855 plane->old_fb = plane->fb;
0856 ret = plane->funcs->disable_plane(plane, ctx);
0857 if (!ret) {
0858 plane->crtc = NULL;
0859 plane->fb = NULL;
0860 } else {
0861 plane->old_fb = NULL;
0862 }
0863 goto out;
0864 }
0865
0866 ret = __setplane_check(plane, crtc, fb,
0867 crtc_x, crtc_y, crtc_w, crtc_h,
0868 src_x, src_y, src_w, src_h);
0869 if (ret)
0870 goto out;
0871
0872 plane->old_fb = plane->fb;
0873 ret = plane->funcs->update_plane(plane, crtc, fb,
0874 crtc_x, crtc_y, crtc_w, crtc_h,
0875 src_x, src_y, src_w, src_h, ctx);
0876 if (!ret) {
0877 plane->crtc = crtc;
0878 plane->fb = fb;
0879 drm_framebuffer_get(plane->fb);
0880 } else {
0881 plane->old_fb = NULL;
0882 }
0883
0884 out:
0885 if (plane->old_fb)
0886 drm_framebuffer_put(plane->old_fb);
0887 plane->old_fb = NULL;
0888
0889 return ret;
0890 }
0891
0892 static int __setplane_atomic(struct drm_plane *plane,
0893 struct drm_crtc *crtc,
0894 struct drm_framebuffer *fb,
0895 int32_t crtc_x, int32_t crtc_y,
0896 uint32_t crtc_w, uint32_t crtc_h,
0897 uint32_t src_x, uint32_t src_y,
0898 uint32_t src_w, uint32_t src_h,
0899 struct drm_modeset_acquire_ctx *ctx)
0900 {
0901 int ret;
0902
0903 WARN_ON(!drm_drv_uses_atomic_modeset(plane->dev));
0904
0905
0906 if (!fb)
0907 return plane->funcs->disable_plane(plane, ctx);
0908
0909
0910
0911
0912
0913
0914
0915
0916 ret = __setplane_check(plane, crtc, fb,
0917 crtc_x, crtc_y, crtc_w, crtc_h,
0918 src_x, src_y, src_w, src_h);
0919 if (ret)
0920 return ret;
0921
0922 return plane->funcs->update_plane(plane, crtc, fb,
0923 crtc_x, crtc_y, crtc_w, crtc_h,
0924 src_x, src_y, src_w, src_h, ctx);
0925 }
0926
0927 static int setplane_internal(struct drm_plane *plane,
0928 struct drm_crtc *crtc,
0929 struct drm_framebuffer *fb,
0930 int32_t crtc_x, int32_t crtc_y,
0931 uint32_t crtc_w, uint32_t crtc_h,
0932
0933 uint32_t src_x, uint32_t src_y,
0934 uint32_t src_w, uint32_t src_h)
0935 {
0936 struct drm_modeset_acquire_ctx ctx;
0937 int ret;
0938
0939 DRM_MODESET_LOCK_ALL_BEGIN(plane->dev, ctx,
0940 DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);
0941
0942 if (drm_drv_uses_atomic_modeset(plane->dev))
0943 ret = __setplane_atomic(plane, crtc, fb,
0944 crtc_x, crtc_y, crtc_w, crtc_h,
0945 src_x, src_y, src_w, src_h, &ctx);
0946 else
0947 ret = __setplane_internal(plane, crtc, fb,
0948 crtc_x, crtc_y, crtc_w, crtc_h,
0949 src_x, src_y, src_w, src_h, &ctx);
0950
0951 DRM_MODESET_LOCK_ALL_END(plane->dev, ctx, ret);
0952
0953 return ret;
0954 }
0955
0956 int drm_mode_setplane(struct drm_device *dev, void *data,
0957 struct drm_file *file_priv)
0958 {
0959 struct drm_mode_set_plane *plane_req = data;
0960 struct drm_plane *plane;
0961 struct drm_crtc *crtc = NULL;
0962 struct drm_framebuffer *fb = NULL;
0963 int ret;
0964
0965 if (!drm_core_check_feature(dev, DRIVER_MODESET))
0966 return -EOPNOTSUPP;
0967
0968
0969
0970
0971
0972 plane = drm_plane_find(dev, file_priv, plane_req->plane_id);
0973 if (!plane) {
0974 DRM_DEBUG_KMS("Unknown plane ID %d\n",
0975 plane_req->plane_id);
0976 return -ENOENT;
0977 }
0978
0979 if (plane_req->fb_id) {
0980 fb = drm_framebuffer_lookup(dev, file_priv, plane_req->fb_id);
0981 if (!fb) {
0982 DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
0983 plane_req->fb_id);
0984 return -ENOENT;
0985 }
0986
0987 crtc = drm_crtc_find(dev, file_priv, plane_req->crtc_id);
0988 if (!crtc) {
0989 drm_framebuffer_put(fb);
0990 DRM_DEBUG_KMS("Unknown crtc ID %d\n",
0991 plane_req->crtc_id);
0992 return -ENOENT;
0993 }
0994 }
0995
0996 ret = setplane_internal(plane, crtc, fb,
0997 plane_req->crtc_x, plane_req->crtc_y,
0998 plane_req->crtc_w, plane_req->crtc_h,
0999 plane_req->src_x, plane_req->src_y,
1000 plane_req->src_w, plane_req->src_h);
1001
1002 if (fb)
1003 drm_framebuffer_put(fb);
1004
1005 return ret;
1006 }
1007
1008 static int drm_mode_cursor_universal(struct drm_crtc *crtc,
1009 struct drm_mode_cursor2 *req,
1010 struct drm_file *file_priv,
1011 struct drm_modeset_acquire_ctx *ctx)
1012 {
1013 struct drm_device *dev = crtc->dev;
1014 struct drm_plane *plane = crtc->cursor;
1015 struct drm_framebuffer *fb = NULL;
1016 struct drm_mode_fb_cmd2 fbreq = {
1017 .width = req->width,
1018 .height = req->height,
1019 .pixel_format = DRM_FORMAT_ARGB8888,
1020 .pitches = { req->width * 4 },
1021 .handles = { req->handle },
1022 };
1023 int32_t crtc_x, crtc_y;
1024 uint32_t crtc_w = 0, crtc_h = 0;
1025 uint32_t src_w = 0, src_h = 0;
1026 int ret = 0;
1027
1028 BUG_ON(!plane);
1029 WARN_ON(plane->crtc != crtc && plane->crtc != NULL);
1030
1031
1032
1033
1034
1035
1036 if (req->flags & DRM_MODE_CURSOR_BO) {
1037 if (req->handle) {
1038 fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv);
1039 if (IS_ERR(fb)) {
1040 DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
1041 return PTR_ERR(fb);
1042 }
1043
1044 fb->hot_x = req->hot_x;
1045 fb->hot_y = req->hot_y;
1046 } else {
1047 fb = NULL;
1048 }
1049 } else {
1050 if (plane->state)
1051 fb = plane->state->fb;
1052 else
1053 fb = plane->fb;
1054
1055 if (fb)
1056 drm_framebuffer_get(fb);
1057 }
1058
1059 if (req->flags & DRM_MODE_CURSOR_MOVE) {
1060 crtc_x = req->x;
1061 crtc_y = req->y;
1062 } else {
1063 crtc_x = crtc->cursor_x;
1064 crtc_y = crtc->cursor_y;
1065 }
1066
1067 if (fb) {
1068 crtc_w = fb->width;
1069 crtc_h = fb->height;
1070 src_w = fb->width << 16;
1071 src_h = fb->height << 16;
1072 }
1073
1074 if (drm_drv_uses_atomic_modeset(dev))
1075 ret = __setplane_atomic(plane, crtc, fb,
1076 crtc_x, crtc_y, crtc_w, crtc_h,
1077 0, 0, src_w, src_h, ctx);
1078 else
1079 ret = __setplane_internal(plane, crtc, fb,
1080 crtc_x, crtc_y, crtc_w, crtc_h,
1081 0, 0, src_w, src_h, ctx);
1082
1083 if (fb)
1084 drm_framebuffer_put(fb);
1085
1086
1087 if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) {
1088 crtc->cursor_x = req->x;
1089 crtc->cursor_y = req->y;
1090 }
1091
1092 return ret;
1093 }
1094
1095 static int drm_mode_cursor_common(struct drm_device *dev,
1096 struct drm_mode_cursor2 *req,
1097 struct drm_file *file_priv)
1098 {
1099 struct drm_crtc *crtc;
1100 struct drm_modeset_acquire_ctx ctx;
1101 int ret = 0;
1102
1103 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1104 return -EOPNOTSUPP;
1105
1106 if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
1107 return -EINVAL;
1108
1109 crtc = drm_crtc_find(dev, file_priv, req->crtc_id);
1110 if (!crtc) {
1111 DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
1112 return -ENOENT;
1113 }
1114
1115 drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
1116 retry:
1117 ret = drm_modeset_lock(&crtc->mutex, &ctx);
1118 if (ret)
1119 goto out;
1120
1121
1122
1123
1124 if (crtc->cursor) {
1125 ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx);
1126 if (ret)
1127 goto out;
1128
1129 if (!drm_lease_held(file_priv, crtc->cursor->base.id)) {
1130 ret = -EACCES;
1131 goto out;
1132 }
1133
1134 ret = drm_mode_cursor_universal(crtc, req, file_priv, &ctx);
1135 goto out;
1136 }
1137
1138 if (req->flags & DRM_MODE_CURSOR_BO) {
1139 if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
1140 ret = -ENXIO;
1141 goto out;
1142 }
1143
1144 if (crtc->funcs->cursor_set2)
1145 ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle,
1146 req->width, req->height, req->hot_x, req->hot_y);
1147 else
1148 ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
1149 req->width, req->height);
1150 }
1151
1152 if (req->flags & DRM_MODE_CURSOR_MOVE) {
1153 if (crtc->funcs->cursor_move) {
1154 ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
1155 } else {
1156 ret = -EFAULT;
1157 goto out;
1158 }
1159 }
1160 out:
1161 if (ret == -EDEADLK) {
1162 ret = drm_modeset_backoff(&ctx);
1163 if (!ret)
1164 goto retry;
1165 }
1166
1167 drm_modeset_drop_locks(&ctx);
1168 drm_modeset_acquire_fini(&ctx);
1169
1170 return ret;
1171
1172 }
1173
1174
1175 int drm_mode_cursor_ioctl(struct drm_device *dev,
1176 void *data, struct drm_file *file_priv)
1177 {
1178 struct drm_mode_cursor *req = data;
1179 struct drm_mode_cursor2 new_req;
1180
1181 memcpy(&new_req, req, sizeof(struct drm_mode_cursor));
1182 new_req.hot_x = new_req.hot_y = 0;
1183
1184 return drm_mode_cursor_common(dev, &new_req, file_priv);
1185 }
1186
1187
1188
1189
1190
1191
1192 int drm_mode_cursor2_ioctl(struct drm_device *dev,
1193 void *data, struct drm_file *file_priv)
1194 {
1195 struct drm_mode_cursor2 *req = data;
1196
1197 return drm_mode_cursor_common(dev, req, file_priv);
1198 }
1199
1200 int drm_mode_page_flip_ioctl(struct drm_device *dev,
1201 void *data, struct drm_file *file_priv)
1202 {
1203 struct drm_mode_crtc_page_flip_target *page_flip = data;
1204 struct drm_crtc *crtc;
1205 struct drm_plane *plane;
1206 struct drm_framebuffer *fb = NULL, *old_fb;
1207 struct drm_pending_vblank_event *e = NULL;
1208 u32 target_vblank = page_flip->sequence;
1209 struct drm_modeset_acquire_ctx ctx;
1210 int ret = -EINVAL;
1211
1212 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1213 return -EOPNOTSUPP;
1214
1215 if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS)
1216 return -EINVAL;
1217
1218 if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET))
1219 return -EINVAL;
1220
1221
1222
1223
1224 if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET)
1225 return -EINVAL;
1226
1227 if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
1228 return -EINVAL;
1229
1230 crtc = drm_crtc_find(dev, file_priv, page_flip->crtc_id);
1231 if (!crtc)
1232 return -ENOENT;
1233
1234 plane = crtc->primary;
1235
1236 if (!drm_lease_held(file_priv, plane->base.id))
1237 return -EACCES;
1238
1239 if (crtc->funcs->page_flip_target) {
1240 u32 current_vblank;
1241 int r;
1242
1243 r = drm_crtc_vblank_get(crtc);
1244 if (r)
1245 return r;
1246
1247 current_vblank = (u32)drm_crtc_vblank_count(crtc);
1248
1249 switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) {
1250 case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE:
1251 if ((int)(target_vblank - current_vblank) > 1) {
1252 DRM_DEBUG("Invalid absolute flip target %u, "
1253 "must be <= %u\n", target_vblank,
1254 current_vblank + 1);
1255 drm_crtc_vblank_put(crtc);
1256 return -EINVAL;
1257 }
1258 break;
1259 case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE:
1260 if (target_vblank != 0 && target_vblank != 1) {
1261 DRM_DEBUG("Invalid relative flip target %u, "
1262 "must be 0 or 1\n", target_vblank);
1263 drm_crtc_vblank_put(crtc);
1264 return -EINVAL;
1265 }
1266 target_vblank += current_vblank;
1267 break;
1268 default:
1269 target_vblank = current_vblank +
1270 !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC);
1271 break;
1272 }
1273 } else if (crtc->funcs->page_flip == NULL ||
1274 (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) {
1275 return -EINVAL;
1276 }
1277
1278 drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
1279 retry:
1280 ret = drm_modeset_lock(&crtc->mutex, &ctx);
1281 if (ret)
1282 goto out;
1283 ret = drm_modeset_lock(&plane->mutex, &ctx);
1284 if (ret)
1285 goto out;
1286
1287 if (plane->state)
1288 old_fb = plane->state->fb;
1289 else
1290 old_fb = plane->fb;
1291
1292 if (old_fb == NULL) {
1293
1294
1295
1296
1297 ret = -EBUSY;
1298 goto out;
1299 }
1300
1301 fb = drm_framebuffer_lookup(dev, file_priv, page_flip->fb_id);
1302 if (!fb) {
1303 ret = -ENOENT;
1304 goto out;
1305 }
1306
1307 if (plane->state) {
1308 const struct drm_plane_state *state = plane->state;
1309
1310 ret = drm_framebuffer_check_src_coords(state->src_x,
1311 state->src_y,
1312 state->src_w,
1313 state->src_h,
1314 fb);
1315 } else {
1316 ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y,
1317 &crtc->mode, fb);
1318 }
1319 if (ret)
1320 goto out;
1321
1322
1323
1324
1325
1326
1327
1328
1329 if (old_fb->format->format != fb->format->format) {
1330 DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
1331 ret = -EINVAL;
1332 goto out;
1333 }
1334
1335 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
1336 e = kzalloc(sizeof *e, GFP_KERNEL);
1337 if (!e) {
1338 ret = -ENOMEM;
1339 goto out;
1340 }
1341
1342 e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
1343 e->event.base.length = sizeof(e->event);
1344 e->event.vbl.user_data = page_flip->user_data;
1345 e->event.vbl.crtc_id = crtc->base.id;
1346
1347 ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
1348 if (ret) {
1349 kfree(e);
1350 e = NULL;
1351 goto out;
1352 }
1353 }
1354
1355 plane->old_fb = plane->fb;
1356 if (crtc->funcs->page_flip_target)
1357 ret = crtc->funcs->page_flip_target(crtc, fb, e,
1358 page_flip->flags,
1359 target_vblank,
1360 &ctx);
1361 else
1362 ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags,
1363 &ctx);
1364 if (ret) {
1365 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT)
1366 drm_event_cancel_free(dev, &e->base);
1367
1368 plane->old_fb = NULL;
1369 } else {
1370 if (!plane->state) {
1371 plane->fb = fb;
1372 drm_framebuffer_get(fb);
1373 }
1374 }
1375
1376 out:
1377 if (fb)
1378 drm_framebuffer_put(fb);
1379 if (plane->old_fb)
1380 drm_framebuffer_put(plane->old_fb);
1381 plane->old_fb = NULL;
1382
1383 if (ret == -EDEADLK) {
1384 ret = drm_modeset_backoff(&ctx);
1385 if (!ret)
1386 goto retry;
1387 }
1388
1389 drm_modeset_drop_locks(&ctx);
1390 drm_modeset_acquire_fini(&ctx);
1391
1392 if (ret && crtc->funcs->page_flip_target)
1393 drm_crtc_vblank_put(crtc);
1394
1395 return ret;
1396 }
1397
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 void drm_plane_enable_fb_damage_clips(struct drm_plane *plane)
1443 {
1444 struct drm_device *dev = plane->dev;
1445 struct drm_mode_config *config = &dev->mode_config;
1446
1447 drm_object_attach_property(&plane->base, config->prop_fb_damage_clips,
1448 0);
1449 }
1450 EXPORT_SYMBOL(drm_plane_enable_fb_damage_clips);
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461 unsigned int
1462 drm_plane_get_damage_clips_count(const struct drm_plane_state *state)
1463 {
1464 return (state && state->fb_damage_clips) ?
1465 state->fb_damage_clips->length/sizeof(struct drm_mode_rect) : 0;
1466 }
1467 EXPORT_SYMBOL(drm_plane_get_damage_clips_count);
1468
1469 struct drm_mode_rect *
1470 __drm_plane_get_damage_clips(const struct drm_plane_state *state)
1471 {
1472 return (struct drm_mode_rect *)((state && state->fb_damage_clips) ?
1473 state->fb_damage_clips->data : NULL);
1474 }
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487 struct drm_mode_rect *
1488 drm_plane_get_damage_clips(const struct drm_plane_state *state)
1489 {
1490 struct drm_device *dev = state->plane->dev;
1491 struct drm_mode_config *config = &dev->mode_config;
1492
1493
1494 if (!drm_mode_obj_find_prop_id(&state->plane->base,
1495 config->prop_fb_damage_clips->base.id))
1496 drm_warn_once(dev, "drm_plane_enable_fb_damage_clips() not called\n");
1497
1498 return __drm_plane_get_damage_clips(state);
1499 }
1500 EXPORT_SYMBOL(drm_plane_get_damage_clips);
1501
1502 struct drm_property *
1503 drm_create_scaling_filter_prop(struct drm_device *dev,
1504 unsigned int supported_filters)
1505 {
1506 struct drm_property *prop;
1507 static const struct drm_prop_enum_list props[] = {
1508 { DRM_SCALING_FILTER_DEFAULT, "Default" },
1509 { DRM_SCALING_FILTER_NEAREST_NEIGHBOR, "Nearest Neighbor" },
1510 };
1511 unsigned int valid_mode_mask = BIT(DRM_SCALING_FILTER_DEFAULT) |
1512 BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR);
1513 int i;
1514
1515 if (WARN_ON((supported_filters & ~valid_mode_mask) ||
1516 ((supported_filters & BIT(DRM_SCALING_FILTER_DEFAULT)) == 0)))
1517 return ERR_PTR(-EINVAL);
1518
1519 prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
1520 "SCALING_FILTER",
1521 hweight32(supported_filters));
1522 if (!prop)
1523 return ERR_PTR(-ENOMEM);
1524
1525 for (i = 0; i < ARRAY_SIZE(props); i++) {
1526 int ret;
1527
1528 if (!(BIT(props[i].type) & supported_filters))
1529 continue;
1530
1531 ret = drm_property_add_enum(prop, props[i].type,
1532 props[i].name);
1533
1534 if (ret) {
1535 drm_property_destroy(dev, prop);
1536
1537 return ERR_PTR(ret);
1538 }
1539 }
1540
1541 return prop;
1542 }
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558 int drm_plane_create_scaling_filter_property(struct drm_plane *plane,
1559 unsigned int supported_filters)
1560 {
1561 struct drm_property *prop =
1562 drm_create_scaling_filter_prop(plane->dev, supported_filters);
1563
1564 if (IS_ERR(prop))
1565 return PTR_ERR(prop);
1566
1567 drm_object_attach_property(&plane->base, prop,
1568 DRM_SCALING_FILTER_DEFAULT);
1569 plane->scaling_filter_property = prop;
1570
1571 return 0;
1572 }
1573 EXPORT_SYMBOL(drm_plane_create_scaling_filter_property);