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