1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29#include <drm/drm_atomic_uapi.h>
30#include <drm/drm_atomic.h>
31#include <drm/drm_print.h>
32#include <drm/drm_drv.h>
33#include <drm/drm_writeback.h>
34#include <drm/drm_vblank.h>
35
36#include <linux/dma-fence.h>
37#include <linux/uaccess.h>
38#include <linux/sync_file.h>
39#include <linux/file.h>
40
41#include "drm_crtc_internal.h"
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
65 const struct drm_display_mode *mode)
66{
67 struct drm_crtc *crtc = state->crtc;
68 struct drm_mode_modeinfo umode;
69
70
71 if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0)
72 return 0;
73
74 drm_property_blob_put(state->mode_blob);
75 state->mode_blob = NULL;
76
77 if (mode) {
78 drm_mode_convert_to_umode(&umode, mode);
79 state->mode_blob =
80 drm_property_create_blob(state->crtc->dev,
81 sizeof(umode),
82 &umode);
83 if (IS_ERR(state->mode_blob))
84 return PTR_ERR(state->mode_blob);
85
86 drm_mode_copy(&state->mode, mode);
87 state->enable = true;
88 DRM_DEBUG_ATOMIC("Set [MODE:%s] for [CRTC:%d:%s] state %p\n",
89 mode->name, crtc->base.id, crtc->name, state);
90 } else {
91 memset(&state->mode, 0, sizeof(state->mode));
92 state->enable = false;
93 DRM_DEBUG_ATOMIC("Set [NOMODE] for [CRTC:%d:%s] state %p\n",
94 crtc->base.id, crtc->name, state);
95 }
96
97 return 0;
98}
99EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc);
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
115 struct drm_property_blob *blob)
116{
117 struct drm_crtc *crtc = state->crtc;
118
119 if (blob == state->mode_blob)
120 return 0;
121
122 drm_property_blob_put(state->mode_blob);
123 state->mode_blob = NULL;
124
125 memset(&state->mode, 0, sizeof(state->mode));
126
127 if (blob) {
128 int ret;
129
130 if (blob->length != sizeof(struct drm_mode_modeinfo)) {
131 DRM_DEBUG_ATOMIC("[CRTC:%d:%s] bad mode blob length: %zu\n",
132 crtc->base.id, crtc->name,
133 blob->length);
134 return -EINVAL;
135 }
136
137 ret = drm_mode_convert_umode(crtc->dev,
138 &state->mode, blob->data);
139 if (ret) {
140 DRM_DEBUG_ATOMIC("[CRTC:%d:%s] invalid mode (ret=%d, status=%s):\n",
141 crtc->base.id, crtc->name,
142 ret, drm_get_mode_status_name(state->mode.status));
143 drm_mode_debug_printmodeline(&state->mode);
144 return -EINVAL;
145 }
146
147 state->mode_blob = drm_property_blob_get(blob);
148 state->enable = true;
149 DRM_DEBUG_ATOMIC("Set [MODE:%s] for [CRTC:%d:%s] state %p\n",
150 state->mode.name, crtc->base.id, crtc->name,
151 state);
152 } else {
153 state->enable = false;
154 DRM_DEBUG_ATOMIC("Set [NOMODE] for [CRTC:%d:%s] state %p\n",
155 crtc->base.id, crtc->name, state);
156 }
157
158 return 0;
159}
160EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176int
177drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
178 struct drm_crtc *crtc)
179{
180 struct drm_plane *plane = plane_state->plane;
181 struct drm_crtc_state *crtc_state;
182
183 if (plane_state->crtc == crtc)
184 return 0;
185 if (plane_state->crtc) {
186 crtc_state = drm_atomic_get_crtc_state(plane_state->state,
187 plane_state->crtc);
188 if (WARN_ON(IS_ERR(crtc_state)))
189 return PTR_ERR(crtc_state);
190
191 crtc_state->plane_mask &= ~drm_plane_mask(plane);
192 }
193
194 plane_state->crtc = crtc;
195
196 if (crtc) {
197 crtc_state = drm_atomic_get_crtc_state(plane_state->state,
198 crtc);
199 if (IS_ERR(crtc_state))
200 return PTR_ERR(crtc_state);
201 crtc_state->plane_mask |= drm_plane_mask(plane);
202 }
203
204 if (crtc)
205 DRM_DEBUG_ATOMIC("Link [PLANE:%d:%s] state %p to [CRTC:%d:%s]\n",
206 plane->base.id, plane->name, plane_state,
207 crtc->base.id, crtc->name);
208 else
209 DRM_DEBUG_ATOMIC("Link [PLANE:%d:%s] state %p to [NOCRTC]\n",
210 plane->base.id, plane->name, plane_state);
211
212 return 0;
213}
214EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
215
216
217
218
219
220
221
222
223
224
225
226void
227drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
228 struct drm_framebuffer *fb)
229{
230 struct drm_plane *plane = plane_state->plane;
231
232 if (fb)
233 DRM_DEBUG_ATOMIC("Set [FB:%d] for [PLANE:%d:%s] state %p\n",
234 fb->base.id, plane->base.id, plane->name,
235 plane_state);
236 else
237 DRM_DEBUG_ATOMIC("Set [NOFB] for [PLANE:%d:%s] state %p\n",
238 plane->base.id, plane->name, plane_state);
239
240 drm_framebuffer_assign(&plane_state->fb, fb);
241}
242EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268void
269drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state,
270 struct dma_fence *fence)
271{
272 if (plane_state->fence) {
273 dma_fence_put(fence);
274 return;
275 }
276
277 plane_state->fence = fence;
278}
279EXPORT_SYMBOL(drm_atomic_set_fence_for_plane);
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295int
296drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
297 struct drm_crtc *crtc)
298{
299 struct drm_connector *connector = conn_state->connector;
300 struct drm_crtc_state *crtc_state;
301
302 if (conn_state->crtc == crtc)
303 return 0;
304
305 if (conn_state->crtc) {
306 crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
307 conn_state->crtc);
308
309 crtc_state->connector_mask &=
310 ~drm_connector_mask(conn_state->connector);
311
312 drm_connector_put(conn_state->connector);
313 conn_state->crtc = NULL;
314 }
315
316 if (crtc) {
317 crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
318 if (IS_ERR(crtc_state))
319 return PTR_ERR(crtc_state);
320
321 crtc_state->connector_mask |=
322 drm_connector_mask(conn_state->connector);
323
324 drm_connector_get(conn_state->connector);
325 conn_state->crtc = crtc;
326
327 DRM_DEBUG_ATOMIC("Link [CONNECTOR:%d:%s] state %p to [CRTC:%d:%s]\n",
328 connector->base.id, connector->name,
329 conn_state, crtc->base.id, crtc->name);
330 } else {
331 DRM_DEBUG_ATOMIC("Link [CONNECTOR:%d:%s] state %p to [NOCRTC]\n",
332 connector->base.id, connector->name,
333 conn_state);
334 }
335
336 return 0;
337}
338EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);
339
340static void set_out_fence_for_crtc(struct drm_atomic_state *state,
341 struct drm_crtc *crtc, s32 __user *fence_ptr)
342{
343 state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = fence_ptr;
344}
345
346static s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state,
347 struct drm_crtc *crtc)
348{
349 s32 __user *fence_ptr;
350
351 fence_ptr = state->crtcs[drm_crtc_index(crtc)].out_fence_ptr;
352 state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = NULL;
353
354 return fence_ptr;
355}
356
357static int set_out_fence_for_connector(struct drm_atomic_state *state,
358 struct drm_connector *connector,
359 s32 __user *fence_ptr)
360{
361 unsigned int index = drm_connector_index(connector);
362
363 if (!fence_ptr)
364 return 0;
365
366 if (put_user(-1, fence_ptr))
367 return -EFAULT;
368
369 state->connectors[index].out_fence_ptr = fence_ptr;
370
371 return 0;
372}
373
374static s32 __user *get_out_fence_for_connector(struct drm_atomic_state *state,
375 struct drm_connector *connector)
376{
377 unsigned int index = drm_connector_index(connector);
378 s32 __user *fence_ptr;
379
380 fence_ptr = state->connectors[index].out_fence_ptr;
381 state->connectors[index].out_fence_ptr = NULL;
382
383 return fence_ptr;
384}
385
386static int
387drm_atomic_replace_property_blob_from_id(struct drm_device *dev,
388 struct drm_property_blob **blob,
389 uint64_t blob_id,
390 ssize_t expected_size,
391 ssize_t expected_elem_size,
392 bool *replaced)
393{
394 struct drm_property_blob *new_blob = NULL;
395
396 if (blob_id != 0) {
397 new_blob = drm_property_lookup_blob(dev, blob_id);
398 if (new_blob == NULL)
399 return -EINVAL;
400
401 if (expected_size > 0 &&
402 new_blob->length != expected_size) {
403 drm_property_blob_put(new_blob);
404 return -EINVAL;
405 }
406 if (expected_elem_size > 0 &&
407 new_blob->length % expected_elem_size != 0) {
408 drm_property_blob_put(new_blob);
409 return -EINVAL;
410 }
411 }
412
413 *replaced |= drm_property_replace_blob(blob, new_blob);
414 drm_property_blob_put(new_blob);
415
416 return 0;
417}
418
419static int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
420 struct drm_crtc_state *state, struct drm_property *property,
421 uint64_t val)
422{
423 struct drm_device *dev = crtc->dev;
424 struct drm_mode_config *config = &dev->mode_config;
425 bool replaced = false;
426 int ret;
427
428 if (property == config->prop_active)
429 state->active = val;
430 else if (property == config->prop_mode_id) {
431 struct drm_property_blob *mode =
432 drm_property_lookup_blob(dev, val);
433 ret = drm_atomic_set_mode_prop_for_crtc(state, mode);
434 drm_property_blob_put(mode);
435 return ret;
436 } else if (property == config->prop_vrr_enabled) {
437 state->vrr_enabled = val;
438 } else if (property == config->degamma_lut_property) {
439 ret = drm_atomic_replace_property_blob_from_id(dev,
440 &state->degamma_lut,
441 val,
442 -1, sizeof(struct drm_color_lut),
443 &replaced);
444 state->color_mgmt_changed |= replaced;
445 return ret;
446 } else if (property == config->ctm_property) {
447 ret = drm_atomic_replace_property_blob_from_id(dev,
448 &state->ctm,
449 val,
450 sizeof(struct drm_color_ctm), -1,
451 &replaced);
452 state->color_mgmt_changed |= replaced;
453 return ret;
454 } else if (property == config->gamma_lut_property) {
455 ret = drm_atomic_replace_property_blob_from_id(dev,
456 &state->gamma_lut,
457 val,
458 -1, sizeof(struct drm_color_lut),
459 &replaced);
460 state->color_mgmt_changed |= replaced;
461 return ret;
462 } else if (property == config->prop_out_fence_ptr) {
463 s32 __user *fence_ptr = u64_to_user_ptr(val);
464
465 if (!fence_ptr)
466 return 0;
467
468 if (put_user(-1, fence_ptr))
469 return -EFAULT;
470
471 set_out_fence_for_crtc(state->state, crtc, fence_ptr);
472 } else if (crtc->funcs->atomic_set_property) {
473 return crtc->funcs->atomic_set_property(crtc, state, property, val);
474 } else {
475 DRM_DEBUG_ATOMIC("[CRTC:%d:%s] unknown property [PROP:%d:%s]]\n",
476 crtc->base.id, crtc->name,
477 property->base.id, property->name);
478 return -EINVAL;
479 }
480
481 return 0;
482}
483
484static int
485drm_atomic_crtc_get_property(struct drm_crtc *crtc,
486 const struct drm_crtc_state *state,
487 struct drm_property *property, uint64_t *val)
488{
489 struct drm_device *dev = crtc->dev;
490 struct drm_mode_config *config = &dev->mode_config;
491
492 if (property == config->prop_active)
493 *val = state->active;
494 else if (property == config->prop_mode_id)
495 *val = (state->mode_blob) ? state->mode_blob->base.id : 0;
496 else if (property == config->prop_vrr_enabled)
497 *val = state->vrr_enabled;
498 else if (property == config->degamma_lut_property)
499 *val = (state->degamma_lut) ? state->degamma_lut->base.id : 0;
500 else if (property == config->ctm_property)
501 *val = (state->ctm) ? state->ctm->base.id : 0;
502 else if (property == config->gamma_lut_property)
503 *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0;
504 else if (property == config->prop_out_fence_ptr)
505 *val = 0;
506 else if (crtc->funcs->atomic_get_property)
507 return crtc->funcs->atomic_get_property(crtc, state, property, val);
508 else
509 return -EINVAL;
510
511 return 0;
512}
513
514static int drm_atomic_plane_set_property(struct drm_plane *plane,
515 struct drm_plane_state *state, struct drm_file *file_priv,
516 struct drm_property *property, uint64_t val)
517{
518 struct drm_device *dev = plane->dev;
519 struct drm_mode_config *config = &dev->mode_config;
520 bool replaced = false;
521 int ret;
522
523 if (property == config->prop_fb_id) {
524 struct drm_framebuffer *fb;
525 fb = drm_framebuffer_lookup(dev, file_priv, val);
526 drm_atomic_set_fb_for_plane(state, fb);
527 if (fb)
528 drm_framebuffer_put(fb);
529 } else if (property == config->prop_in_fence_fd) {
530 if (state->fence)
531 return -EINVAL;
532
533 if (U642I64(val) == -1)
534 return 0;
535
536 state->fence = sync_file_get_fence(val);
537 if (!state->fence)
538 return -EINVAL;
539
540 } else if (property == config->prop_crtc_id) {
541 struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val);
542 if (val && !crtc)
543 return -EACCES;
544 return drm_atomic_set_crtc_for_plane(state, crtc);
545 } else if (property == config->prop_crtc_x) {
546 state->crtc_x = U642I64(val);
547 } else if (property == config->prop_crtc_y) {
548 state->crtc_y = U642I64(val);
549 } else if (property == config->prop_crtc_w) {
550 state->crtc_w = val;
551 } else if (property == config->prop_crtc_h) {
552 state->crtc_h = val;
553 } else if (property == config->prop_src_x) {
554 state->src_x = val;
555 } else if (property == config->prop_src_y) {
556 state->src_y = val;
557 } else if (property == config->prop_src_w) {
558 state->src_w = val;
559 } else if (property == config->prop_src_h) {
560 state->src_h = val;
561 } else if (property == plane->alpha_property) {
562 state->alpha = val;
563 } else if (property == plane->blend_mode_property) {
564 state->pixel_blend_mode = val;
565 } else if (property == plane->rotation_property) {
566 if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK)) {
567 DRM_DEBUG_ATOMIC("[PLANE:%d:%s] bad rotation bitmask: 0x%llx\n",
568 plane->base.id, plane->name, val);
569 return -EINVAL;
570 }
571 state->rotation = val;
572 } else if (property == plane->zpos_property) {
573 state->zpos = val;
574 } else if (property == plane->color_encoding_property) {
575 state->color_encoding = val;
576 } else if (property == plane->color_range_property) {
577 state->color_range = val;
578 } else if (property == config->prop_fb_damage_clips) {
579 ret = drm_atomic_replace_property_blob_from_id(dev,
580 &state->fb_damage_clips,
581 val,
582 -1,
583 sizeof(struct drm_rect),
584 &replaced);
585 return ret;
586 } else if (plane->funcs->atomic_set_property) {
587 return plane->funcs->atomic_set_property(plane, state,
588 property, val);
589 } else {
590 DRM_DEBUG_ATOMIC("[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n",
591 plane->base.id, plane->name,
592 property->base.id, property->name);
593 return -EINVAL;
594 }
595
596 return 0;
597}
598
599static int
600drm_atomic_plane_get_property(struct drm_plane *plane,
601 const struct drm_plane_state *state,
602 struct drm_property *property, uint64_t *val)
603{
604 struct drm_device *dev = plane->dev;
605 struct drm_mode_config *config = &dev->mode_config;
606
607 if (property == config->prop_fb_id) {
608 *val = (state->fb) ? state->fb->base.id : 0;
609 } else if (property == config->prop_in_fence_fd) {
610 *val = -1;
611 } else if (property == config->prop_crtc_id) {
612 *val = (state->crtc) ? state->crtc->base.id : 0;
613 } else if (property == config->prop_crtc_x) {
614 *val = I642U64(state->crtc_x);
615 } else if (property == config->prop_crtc_y) {
616 *val = I642U64(state->crtc_y);
617 } else if (property == config->prop_crtc_w) {
618 *val = state->crtc_w;
619 } else if (property == config->prop_crtc_h) {
620 *val = state->crtc_h;
621 } else if (property == config->prop_src_x) {
622 *val = state->src_x;
623 } else if (property == config->prop_src_y) {
624 *val = state->src_y;
625 } else if (property == config->prop_src_w) {
626 *val = state->src_w;
627 } else if (property == config->prop_src_h) {
628 *val = state->src_h;
629 } else if (property == plane->alpha_property) {
630 *val = state->alpha;
631 } else if (property == plane->blend_mode_property) {
632 *val = state->pixel_blend_mode;
633 } else if (property == plane->rotation_property) {
634 *val = state->rotation;
635 } else if (property == plane->zpos_property) {
636 *val = state->zpos;
637 } else if (property == plane->color_encoding_property) {
638 *val = state->color_encoding;
639 } else if (property == plane->color_range_property) {
640 *val = state->color_range;
641 } else if (property == config->prop_fb_damage_clips) {
642 *val = (state->fb_damage_clips) ?
643 state->fb_damage_clips->base.id : 0;
644 } else if (plane->funcs->atomic_get_property) {
645 return plane->funcs->atomic_get_property(plane, state, property, val);
646 } else {
647 return -EINVAL;
648 }
649
650 return 0;
651}
652
653static int drm_atomic_set_writeback_fb_for_connector(
654 struct drm_connector_state *conn_state,
655 struct drm_framebuffer *fb)
656{
657 int ret;
658
659 ret = drm_writeback_set_fb(conn_state, fb);
660 if (ret < 0)
661 return ret;
662
663 if (fb)
664 DRM_DEBUG_ATOMIC("Set [FB:%d] for connector state %p\n",
665 fb->base.id, conn_state);
666 else
667 DRM_DEBUG_ATOMIC("Set [NOFB] for connector state %p\n",
668 conn_state);
669
670 return 0;
671}
672
673static int drm_atomic_connector_set_property(struct drm_connector *connector,
674 struct drm_connector_state *state, struct drm_file *file_priv,
675 struct drm_property *property, uint64_t val)
676{
677 struct drm_device *dev = connector->dev;
678 struct drm_mode_config *config = &dev->mode_config;
679
680 if (property == config->prop_crtc_id) {
681 struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val);
682 if (val && !crtc)
683 return -EACCES;
684 return drm_atomic_set_crtc_for_connector(state, crtc);
685 } else if (property == config->dpms_property) {
686
687
688
689
690 return -EINVAL;
691 } else if (property == config->tv_select_subconnector_property) {
692 state->tv.subconnector = val;
693 } else if (property == config->tv_left_margin_property) {
694 state->tv.margins.left = val;
695 } else if (property == config->tv_right_margin_property) {
696 state->tv.margins.right = val;
697 } else if (property == config->tv_top_margin_property) {
698 state->tv.margins.top = val;
699 } else if (property == config->tv_bottom_margin_property) {
700 state->tv.margins.bottom = val;
701 } else if (property == config->tv_mode_property) {
702 state->tv.mode = val;
703 } else if (property == config->tv_brightness_property) {
704 state->tv.brightness = val;
705 } else if (property == config->tv_contrast_property) {
706 state->tv.contrast = val;
707 } else if (property == config->tv_flicker_reduction_property) {
708 state->tv.flicker_reduction = val;
709 } else if (property == config->tv_overscan_property) {
710 state->tv.overscan = val;
711 } else if (property == config->tv_saturation_property) {
712 state->tv.saturation = val;
713 } else if (property == config->tv_hue_property) {
714 state->tv.hue = val;
715 } else if (property == config->link_status_property) {
716
717
718
719
720
721
722
723
724
725
726
727 if (state->link_status != DRM_LINK_STATUS_GOOD)
728 state->link_status = val;
729 } else if (property == config->aspect_ratio_property) {
730 state->picture_aspect_ratio = val;
731 } else if (property == config->content_type_property) {
732 state->content_type = val;
733 } else if (property == connector->scaling_mode_property) {
734 state->scaling_mode = val;
735 } else if (property == connector->content_protection_property) {
736 if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
737 DRM_DEBUG_KMS("only drivers can set CP Enabled\n");
738 return -EINVAL;
739 }
740 state->content_protection = val;
741 } else if (property == connector->colorspace_property) {
742 state->colorspace = val;
743 } else if (property == config->writeback_fb_id_property) {
744 struct drm_framebuffer *fb;
745 int ret;
746 fb = drm_framebuffer_lookup(dev, file_priv, val);
747 ret = drm_atomic_set_writeback_fb_for_connector(state, fb);
748 if (fb)
749 drm_framebuffer_put(fb);
750 return ret;
751 } else if (property == config->writeback_out_fence_ptr_property) {
752 s32 __user *fence_ptr = u64_to_user_ptr(val);
753
754 return set_out_fence_for_connector(state->state, connector,
755 fence_ptr);
756 } else if (property == connector->max_bpc_property) {
757 state->max_requested_bpc = val;
758 } else if (connector->funcs->atomic_set_property) {
759 return connector->funcs->atomic_set_property(connector,
760 state, property, val);
761 } else {
762 DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] unknown property [PROP:%d:%s]]\n",
763 connector->base.id, connector->name,
764 property->base.id, property->name);
765 return -EINVAL;
766 }
767
768 return 0;
769}
770
771static int
772drm_atomic_connector_get_property(struct drm_connector *connector,
773 const struct drm_connector_state *state,
774 struct drm_property *property, uint64_t *val)
775{
776 struct drm_device *dev = connector->dev;
777 struct drm_mode_config *config = &dev->mode_config;
778
779 if (property == config->prop_crtc_id) {
780 *val = (state->crtc) ? state->crtc->base.id : 0;
781 } else if (property == config->dpms_property) {
782 *val = connector->dpms;
783 } else if (property == config->tv_select_subconnector_property) {
784 *val = state->tv.subconnector;
785 } else if (property == config->tv_left_margin_property) {
786 *val = state->tv.margins.left;
787 } else if (property == config->tv_right_margin_property) {
788 *val = state->tv.margins.right;
789 } else if (property == config->tv_top_margin_property) {
790 *val = state->tv.margins.top;
791 } else if (property == config->tv_bottom_margin_property) {
792 *val = state->tv.margins.bottom;
793 } else if (property == config->tv_mode_property) {
794 *val = state->tv.mode;
795 } else if (property == config->tv_brightness_property) {
796 *val = state->tv.brightness;
797 } else if (property == config->tv_contrast_property) {
798 *val = state->tv.contrast;
799 } else if (property == config->tv_flicker_reduction_property) {
800 *val = state->tv.flicker_reduction;
801 } else if (property == config->tv_overscan_property) {
802 *val = state->tv.overscan;
803 } else if (property == config->tv_saturation_property) {
804 *val = state->tv.saturation;
805 } else if (property == config->tv_hue_property) {
806 *val = state->tv.hue;
807 } else if (property == config->link_status_property) {
808 *val = state->link_status;
809 } else if (property == config->aspect_ratio_property) {
810 *val = state->picture_aspect_ratio;
811 } else if (property == config->content_type_property) {
812 *val = state->content_type;
813 } else if (property == connector->colorspace_property) {
814 *val = state->colorspace;
815 } else if (property == connector->scaling_mode_property) {
816 *val = state->scaling_mode;
817 } else if (property == connector->content_protection_property) {
818 *val = state->content_protection;
819 } else if (property == config->writeback_fb_id_property) {
820
821 *val = 0;
822 } else if (property == config->writeback_out_fence_ptr_property) {
823 *val = 0;
824 } else if (property == connector->max_bpc_property) {
825 *val = state->max_requested_bpc;
826 } else if (connector->funcs->atomic_get_property) {
827 return connector->funcs->atomic_get_property(connector,
828 state, property, val);
829 } else {
830 return -EINVAL;
831 }
832
833 return 0;
834}
835
836int drm_atomic_get_property(struct drm_mode_object *obj,
837 struct drm_property *property, uint64_t *val)
838{
839 struct drm_device *dev = property->dev;
840 int ret;
841
842 switch (obj->type) {
843 case DRM_MODE_OBJECT_CONNECTOR: {
844 struct drm_connector *connector = obj_to_connector(obj);
845 WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
846 ret = drm_atomic_connector_get_property(connector,
847 connector->state, property, val);
848 break;
849 }
850 case DRM_MODE_OBJECT_CRTC: {
851 struct drm_crtc *crtc = obj_to_crtc(obj);
852 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
853 ret = drm_atomic_crtc_get_property(crtc,
854 crtc->state, property, val);
855 break;
856 }
857 case DRM_MODE_OBJECT_PLANE: {
858 struct drm_plane *plane = obj_to_plane(obj);
859 WARN_ON(!drm_modeset_is_locked(&plane->mutex));
860 ret = drm_atomic_plane_get_property(plane,
861 plane->state, property, val);
862 break;
863 }
864 default:
865 ret = -EINVAL;
866 break;
867 }
868
869 return ret;
870}
871
872
873
874
875
876static struct drm_pending_vblank_event *create_vblank_event(
877 struct drm_crtc *crtc, uint64_t user_data)
878{
879 struct drm_pending_vblank_event *e = NULL;
880
881 e = kzalloc(sizeof *e, GFP_KERNEL);
882 if (!e)
883 return NULL;
884
885 e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
886 e->event.base.length = sizeof(e->event);
887 e->event.vbl.crtc_id = crtc->base.id;
888 e->event.vbl.user_data = user_data;
889
890 return e;
891}
892
893int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state,
894 struct drm_connector *connector,
895 int mode)
896{
897 struct drm_connector *tmp_connector;
898 struct drm_connector_state *new_conn_state;
899 struct drm_crtc *crtc;
900 struct drm_crtc_state *crtc_state;
901 int i, ret, old_mode = connector->dpms;
902 bool active = false;
903
904 ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
905 state->acquire_ctx);
906 if (ret)
907 return ret;
908
909 if (mode != DRM_MODE_DPMS_ON)
910 mode = DRM_MODE_DPMS_OFF;
911 connector->dpms = mode;
912
913 crtc = connector->state->crtc;
914 if (!crtc)
915 goto out;
916 ret = drm_atomic_add_affected_connectors(state, crtc);
917 if (ret)
918 goto out;
919
920 crtc_state = drm_atomic_get_crtc_state(state, crtc);
921 if (IS_ERR(crtc_state)) {
922 ret = PTR_ERR(crtc_state);
923 goto out;
924 }
925
926 for_each_new_connector_in_state(state, tmp_connector, new_conn_state, i) {
927 if (new_conn_state->crtc != crtc)
928 continue;
929 if (tmp_connector->dpms == DRM_MODE_DPMS_ON) {
930 active = true;
931 break;
932 }
933 }
934
935 crtc_state->active = active;
936 ret = drm_atomic_commit(state);
937out:
938 if (ret != 0)
939 connector->dpms = old_mode;
940 return ret;
941}
942
943int drm_atomic_set_property(struct drm_atomic_state *state,
944 struct drm_file *file_priv,
945 struct drm_mode_object *obj,
946 struct drm_property *prop,
947 uint64_t prop_value)
948{
949 struct drm_mode_object *ref;
950 int ret;
951
952 if (!drm_property_change_valid_get(prop, prop_value, &ref))
953 return -EINVAL;
954
955 switch (obj->type) {
956 case DRM_MODE_OBJECT_CONNECTOR: {
957 struct drm_connector *connector = obj_to_connector(obj);
958 struct drm_connector_state *connector_state;
959
960 connector_state = drm_atomic_get_connector_state(state, connector);
961 if (IS_ERR(connector_state)) {
962 ret = PTR_ERR(connector_state);
963 break;
964 }
965
966 ret = drm_atomic_connector_set_property(connector,
967 connector_state, file_priv,
968 prop, prop_value);
969 break;
970 }
971 case DRM_MODE_OBJECT_CRTC: {
972 struct drm_crtc *crtc = obj_to_crtc(obj);
973 struct drm_crtc_state *crtc_state;
974
975 crtc_state = drm_atomic_get_crtc_state(state, crtc);
976 if (IS_ERR(crtc_state)) {
977 ret = PTR_ERR(crtc_state);
978 break;
979 }
980
981 ret = drm_atomic_crtc_set_property(crtc,
982 crtc_state, prop, prop_value);
983 break;
984 }
985 case DRM_MODE_OBJECT_PLANE: {
986 struct drm_plane *plane = obj_to_plane(obj);
987 struct drm_plane_state *plane_state;
988
989 plane_state = drm_atomic_get_plane_state(state, plane);
990 if (IS_ERR(plane_state)) {
991 ret = PTR_ERR(plane_state);
992 break;
993 }
994
995 ret = drm_atomic_plane_set_property(plane,
996 plane_state, file_priv,
997 prop, prop_value);
998 break;
999 }
1000 default:
1001 ret = -EINVAL;
1002 break;
1003 }
1004
1005 drm_property_change_valid_put(prop, ref);
1006 return ret;
1007}
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061struct drm_out_fence_state {
1062 s32 __user *out_fence_ptr;
1063 struct sync_file *sync_file;
1064 int fd;
1065};
1066
1067static int setup_out_fence(struct drm_out_fence_state *fence_state,
1068 struct dma_fence *fence)
1069{
1070 fence_state->fd = get_unused_fd_flags(O_CLOEXEC);
1071 if (fence_state->fd < 0)
1072 return fence_state->fd;
1073
1074 if (put_user(fence_state->fd, fence_state->out_fence_ptr))
1075 return -EFAULT;
1076
1077 fence_state->sync_file = sync_file_create(fence);
1078 if (!fence_state->sync_file)
1079 return -ENOMEM;
1080
1081 return 0;
1082}
1083
1084static int prepare_signaling(struct drm_device *dev,
1085 struct drm_atomic_state *state,
1086 struct drm_mode_atomic *arg,
1087 struct drm_file *file_priv,
1088 struct drm_out_fence_state **fence_state,
1089 unsigned int *num_fences)
1090{
1091 struct drm_crtc *crtc;
1092 struct drm_crtc_state *crtc_state;
1093 struct drm_connector *conn;
1094 struct drm_connector_state *conn_state;
1095 int i, c = 0, ret;
1096
1097 if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
1098 return 0;
1099
1100 for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
1101 s32 __user *fence_ptr;
1102
1103 fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc);
1104
1105 if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) {
1106 struct drm_pending_vblank_event *e;
1107
1108 e = create_vblank_event(crtc, arg->user_data);
1109 if (!e)
1110 return -ENOMEM;
1111
1112 crtc_state->event = e;
1113 }
1114
1115 if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
1116 struct drm_pending_vblank_event *e = crtc_state->event;
1117
1118 if (!file_priv)
1119 continue;
1120
1121 ret = drm_event_reserve_init(dev, file_priv, &e->base,
1122 &e->event.base);
1123 if (ret) {
1124 kfree(e);
1125 crtc_state->event = NULL;
1126 return ret;
1127 }
1128 }
1129
1130 if (fence_ptr) {
1131 struct dma_fence *fence;
1132 struct drm_out_fence_state *f;
1133
1134 f = krealloc(*fence_state, sizeof(**fence_state) *
1135 (*num_fences + 1), GFP_KERNEL);
1136 if (!f)
1137 return -ENOMEM;
1138
1139 memset(&f[*num_fences], 0, sizeof(*f));
1140
1141 f[*num_fences].out_fence_ptr = fence_ptr;
1142 *fence_state = f;
1143
1144 fence = drm_crtc_create_fence(crtc);
1145 if (!fence)
1146 return -ENOMEM;
1147
1148 ret = setup_out_fence(&f[(*num_fences)++], fence);
1149 if (ret) {
1150 dma_fence_put(fence);
1151 return ret;
1152 }
1153
1154 crtc_state->event->base.fence = fence;
1155 }
1156
1157 c++;
1158 }
1159
1160 for_each_new_connector_in_state(state, conn, conn_state, i) {
1161 struct drm_writeback_connector *wb_conn;
1162 struct drm_out_fence_state *f;
1163 struct dma_fence *fence;
1164 s32 __user *fence_ptr;
1165
1166 if (!conn_state->writeback_job)
1167 continue;
1168
1169 fence_ptr = get_out_fence_for_connector(state, conn);
1170 if (!fence_ptr)
1171 continue;
1172
1173 f = krealloc(*fence_state, sizeof(**fence_state) *
1174 (*num_fences + 1), GFP_KERNEL);
1175 if (!f)
1176 return -ENOMEM;
1177
1178 memset(&f[*num_fences], 0, sizeof(*f));
1179
1180 f[*num_fences].out_fence_ptr = fence_ptr;
1181 *fence_state = f;
1182
1183 wb_conn = drm_connector_to_writeback(conn);
1184 fence = drm_writeback_get_out_fence(wb_conn);
1185 if (!fence)
1186 return -ENOMEM;
1187
1188 ret = setup_out_fence(&f[(*num_fences)++], fence);
1189 if (ret) {
1190 dma_fence_put(fence);
1191 return ret;
1192 }
1193
1194 conn_state->writeback_job->out_fence = fence;
1195 }
1196
1197
1198
1199
1200
1201 if (c == 0 && (arg->flags & DRM_MODE_PAGE_FLIP_EVENT))
1202 return -EINVAL;
1203
1204 return 0;
1205}
1206
1207static void complete_signaling(struct drm_device *dev,
1208 struct drm_atomic_state *state,
1209 struct drm_out_fence_state *fence_state,
1210 unsigned int num_fences,
1211 bool install_fds)
1212{
1213 struct drm_crtc *crtc;
1214 struct drm_crtc_state *crtc_state;
1215 int i;
1216
1217 if (install_fds) {
1218 for (i = 0; i < num_fences; i++)
1219 fd_install(fence_state[i].fd,
1220 fence_state[i].sync_file->file);
1221
1222 kfree(fence_state);
1223 return;
1224 }
1225
1226 for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
1227 struct drm_pending_vblank_event *event = crtc_state->event;
1228
1229
1230
1231
1232
1233 if (event && (event->base.fence || event->base.file_priv)) {
1234 drm_event_cancel_free(dev, &event->base);
1235 crtc_state->event = NULL;
1236 }
1237 }
1238
1239 if (!fence_state)
1240 return;
1241
1242 for (i = 0; i < num_fences; i++) {
1243 if (fence_state[i].sync_file)
1244 fput(fence_state[i].sync_file->file);
1245 if (fence_state[i].fd >= 0)
1246 put_unused_fd(fence_state[i].fd);
1247
1248
1249 if (fence_state[i].out_fence_ptr &&
1250 put_user(-1, fence_state[i].out_fence_ptr))
1251 DRM_DEBUG_ATOMIC("Couldn't clear out_fence_ptr\n");
1252 }
1253
1254 kfree(fence_state);
1255}
1256
1257int drm_mode_atomic_ioctl(struct drm_device *dev,
1258 void *data, struct drm_file *file_priv)
1259{
1260 struct drm_mode_atomic *arg = data;
1261 uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
1262 uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
1263 uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
1264 uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
1265 unsigned int copied_objs, copied_props;
1266 struct drm_atomic_state *state;
1267 struct drm_modeset_acquire_ctx ctx;
1268 struct drm_out_fence_state *fence_state;
1269 int ret = 0;
1270 unsigned int i, j, num_fences;
1271
1272
1273 if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
1274 return -EOPNOTSUPP;
1275
1276
1277
1278
1279
1280 if (!file_priv->atomic)
1281 return -EINVAL;
1282
1283 if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS)
1284 return -EINVAL;
1285
1286 if (arg->reserved)
1287 return -EINVAL;
1288
1289 if ((arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) &&
1290 !dev->mode_config.async_page_flip)
1291 return -EINVAL;
1292
1293
1294 if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
1295 (arg->flags & DRM_MODE_PAGE_FLIP_EVENT))
1296 return -EINVAL;
1297
1298 state = drm_atomic_state_alloc(dev);
1299 if (!state)
1300 return -ENOMEM;
1301
1302 drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
1303 state->acquire_ctx = &ctx;
1304 state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);
1305
1306retry:
1307 copied_objs = 0;
1308 copied_props = 0;
1309 fence_state = NULL;
1310 num_fences = 0;
1311
1312 for (i = 0; i < arg->count_objs; i++) {
1313 uint32_t obj_id, count_props;
1314 struct drm_mode_object *obj;
1315
1316 if (get_user(obj_id, objs_ptr + copied_objs)) {
1317 ret = -EFAULT;
1318 goto out;
1319 }
1320
1321 obj = drm_mode_object_find(dev, file_priv, obj_id, DRM_MODE_OBJECT_ANY);
1322 if (!obj) {
1323 ret = -ENOENT;
1324 goto out;
1325 }
1326
1327 if (!obj->properties) {
1328 drm_mode_object_put(obj);
1329 ret = -ENOENT;
1330 goto out;
1331 }
1332
1333 if (get_user(count_props, count_props_ptr + copied_objs)) {
1334 drm_mode_object_put(obj);
1335 ret = -EFAULT;
1336 goto out;
1337 }
1338
1339 copied_objs++;
1340
1341 for (j = 0; j < count_props; j++) {
1342 uint32_t prop_id;
1343 uint64_t prop_value;
1344 struct drm_property *prop;
1345
1346 if (get_user(prop_id, props_ptr + copied_props)) {
1347 drm_mode_object_put(obj);
1348 ret = -EFAULT;
1349 goto out;
1350 }
1351
1352 prop = drm_mode_obj_find_prop_id(obj, prop_id);
1353 if (!prop) {
1354 drm_mode_object_put(obj);
1355 ret = -ENOENT;
1356 goto out;
1357 }
1358
1359 if (copy_from_user(&prop_value,
1360 prop_values_ptr + copied_props,
1361 sizeof(prop_value))) {
1362 drm_mode_object_put(obj);
1363 ret = -EFAULT;
1364 goto out;
1365 }
1366
1367 ret = drm_atomic_set_property(state, file_priv,
1368 obj, prop, prop_value);
1369 if (ret) {
1370 drm_mode_object_put(obj);
1371 goto out;
1372 }
1373
1374 copied_props++;
1375 }
1376
1377 drm_mode_object_put(obj);
1378 }
1379
1380 ret = prepare_signaling(dev, state, arg, file_priv, &fence_state,
1381 &num_fences);
1382 if (ret)
1383 goto out;
1384
1385 if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) {
1386 ret = drm_atomic_check_only(state);
1387 } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) {
1388 ret = drm_atomic_nonblocking_commit(state);
1389 } else {
1390 if (unlikely(drm_debug & DRM_UT_STATE))
1391 drm_atomic_print_state(state);
1392
1393 ret = drm_atomic_commit(state);
1394 }
1395
1396out:
1397 complete_signaling(dev, state, fence_state, num_fences, !ret);
1398
1399 if (ret == -EDEADLK) {
1400 drm_atomic_state_clear(state);
1401 ret = drm_modeset_backoff(&ctx);
1402 if (!ret)
1403 goto retry;
1404 }
1405
1406 drm_atomic_state_put(state);
1407
1408 drm_modeset_drop_locks(&ctx);
1409 drm_modeset_acquire_fini(&ctx);
1410
1411 return ret;
1412}
1413