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->aspect_ratio_property) {
769 state->picture_aspect_ratio = val;
770 } else if (property == config->content_type_property) {
771 state->content_type = val;
772 } else if (property == connector->scaling_mode_property) {
773 state->scaling_mode = val;
774 } else if (property == config->content_protection_property) {
775 if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
776 DRM_DEBUG_KMS("only drivers can set CP Enabled\n");
777 return -EINVAL;
778 }
779 state->content_protection = val;
780 } else if (property == config->hdcp_content_type_property) {
781 state->hdcp_content_type = val;
782 } else if (property == connector->colorspace_property) {
783 state->colorspace = val;
784 } else if (property == config->writeback_fb_id_property) {
785 struct drm_framebuffer *fb;
786 int ret;
787
788 fb = drm_framebuffer_lookup(dev, file_priv, val);
789 ret = drm_atomic_set_writeback_fb_for_connector(state, fb);
790 if (fb)
791 drm_framebuffer_put(fb);
792 return ret;
793 } else if (property == config->writeback_out_fence_ptr_property) {
794 s32 __user *fence_ptr = u64_to_user_ptr(val);
795
796 return set_out_fence_for_connector(state->state, connector,
797 fence_ptr);
798 } else if (property == connector->max_bpc_property) {
799 state->max_requested_bpc = val;
800 } else if (connector->funcs->atomic_set_property) {
801 return connector->funcs->atomic_set_property(connector,
802 state, property, val);
803 } else {
804 drm_dbg_atomic(connector->dev,
805 "[CONNECTOR:%d:%s] unknown property [PROP:%d:%s]]\n",
806 connector->base.id, connector->name,
807 property->base.id, property->name);
808 return -EINVAL;
809 }
810
811 return 0;
812}
813
814static int
815drm_atomic_connector_get_property(struct drm_connector *connector,
816 const struct drm_connector_state *state,
817 struct drm_property *property, uint64_t *val)
818{
819 struct drm_device *dev = connector->dev;
820 struct drm_mode_config *config = &dev->mode_config;
821
822 if (property == config->prop_crtc_id) {
823 *val = (state->crtc) ? state->crtc->base.id : 0;
824 } else if (property == config->dpms_property) {
825 if (state->crtc && state->crtc->state->self_refresh_active)
826 *val = DRM_MODE_DPMS_ON;
827 else
828 *val = connector->dpms;
829 } else if (property == config->tv_select_subconnector_property) {
830 *val = state->tv.subconnector;
831 } else if (property == config->tv_left_margin_property) {
832 *val = state->tv.margins.left;
833 } else if (property == config->tv_right_margin_property) {
834 *val = state->tv.margins.right;
835 } else if (property == config->tv_top_margin_property) {
836 *val = state->tv.margins.top;
837 } else if (property == config->tv_bottom_margin_property) {
838 *val = state->tv.margins.bottom;
839 } else if (property == config->tv_mode_property) {
840 *val = state->tv.mode;
841 } else if (property == config->tv_brightness_property) {
842 *val = state->tv.brightness;
843 } else if (property == config->tv_contrast_property) {
844 *val = state->tv.contrast;
845 } else if (property == config->tv_flicker_reduction_property) {
846 *val = state->tv.flicker_reduction;
847 } else if (property == config->tv_overscan_property) {
848 *val = state->tv.overscan;
849 } else if (property == config->tv_saturation_property) {
850 *val = state->tv.saturation;
851 } else if (property == config->tv_hue_property) {
852 *val = state->tv.hue;
853 } else if (property == config->link_status_property) {
854 *val = state->link_status;
855 } else if (property == config->aspect_ratio_property) {
856 *val = state->picture_aspect_ratio;
857 } else if (property == config->content_type_property) {
858 *val = state->content_type;
859 } else if (property == connector->colorspace_property) {
860 *val = state->colorspace;
861 } else if (property == connector->scaling_mode_property) {
862 *val = state->scaling_mode;
863 } else if (property == config->hdr_output_metadata_property) {
864 *val = state->hdr_output_metadata ?
865 state->hdr_output_metadata->base.id : 0;
866 } else if (property == config->content_protection_property) {
867 *val = state->content_protection;
868 } else if (property == config->hdcp_content_type_property) {
869 *val = state->hdcp_content_type;
870 } else if (property == config->writeback_fb_id_property) {
871
872 *val = 0;
873 } else if (property == config->writeback_out_fence_ptr_property) {
874 *val = 0;
875 } else if (property == connector->max_bpc_property) {
876 *val = state->max_requested_bpc;
877 } else if (connector->funcs->atomic_get_property) {
878 return connector->funcs->atomic_get_property(connector,
879 state, property, val);
880 } else {
881 return -EINVAL;
882 }
883
884 return 0;
885}
886
887int drm_atomic_get_property(struct drm_mode_object *obj,
888 struct drm_property *property, uint64_t *val)
889{
890 struct drm_device *dev = property->dev;
891 int ret;
892
893 switch (obj->type) {
894 case DRM_MODE_OBJECT_CONNECTOR: {
895 struct drm_connector *connector = obj_to_connector(obj);
896
897 WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
898 ret = drm_atomic_connector_get_property(connector,
899 connector->state, property, val);
900 break;
901 }
902 case DRM_MODE_OBJECT_CRTC: {
903 struct drm_crtc *crtc = obj_to_crtc(obj);
904
905 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
906 ret = drm_atomic_crtc_get_property(crtc,
907 crtc->state, property, val);
908 break;
909 }
910 case DRM_MODE_OBJECT_PLANE: {
911 struct drm_plane *plane = obj_to_plane(obj);
912
913 WARN_ON(!drm_modeset_is_locked(&plane->mutex));
914 ret = drm_atomic_plane_get_property(plane,
915 plane->state, property, val);
916 break;
917 }
918 default:
919 ret = -EINVAL;
920 break;
921 }
922
923 return ret;
924}
925
926
927
928
929
930static struct drm_pending_vblank_event *create_vblank_event(
931 struct drm_crtc *crtc, uint64_t user_data)
932{
933 struct drm_pending_vblank_event *e = NULL;
934
935 e = kzalloc(sizeof *e, GFP_KERNEL);
936 if (!e)
937 return NULL;
938
939 e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
940 e->event.base.length = sizeof(e->event);
941 e->event.vbl.crtc_id = crtc->base.id;
942 e->event.vbl.user_data = user_data;
943
944 return e;
945}
946
947int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state,
948 struct drm_connector *connector,
949 int mode)
950{
951 struct drm_connector *tmp_connector;
952 struct drm_connector_state *new_conn_state;
953 struct drm_crtc *crtc;
954 struct drm_crtc_state *crtc_state;
955 int i, ret, old_mode = connector->dpms;
956 bool active = false;
957
958 ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
959 state->acquire_ctx);
960 if (ret)
961 return ret;
962
963 if (mode != DRM_MODE_DPMS_ON)
964 mode = DRM_MODE_DPMS_OFF;
965 connector->dpms = mode;
966
967 crtc = connector->state->crtc;
968 if (!crtc)
969 goto out;
970 ret = drm_atomic_add_affected_connectors(state, crtc);
971 if (ret)
972 goto out;
973
974 crtc_state = drm_atomic_get_crtc_state(state, crtc);
975 if (IS_ERR(crtc_state)) {
976 ret = PTR_ERR(crtc_state);
977 goto out;
978 }
979
980 for_each_new_connector_in_state(state, tmp_connector, new_conn_state, i) {
981 if (new_conn_state->crtc != crtc)
982 continue;
983 if (tmp_connector->dpms == DRM_MODE_DPMS_ON) {
984 active = true;
985 break;
986 }
987 }
988
989 crtc_state->active = active;
990 ret = drm_atomic_commit(state);
991out:
992 if (ret != 0)
993 connector->dpms = old_mode;
994 return ret;
995}
996
997int drm_atomic_set_property(struct drm_atomic_state *state,
998 struct drm_file *file_priv,
999 struct drm_mode_object *obj,
1000 struct drm_property *prop,
1001 uint64_t prop_value)
1002{
1003 struct drm_mode_object *ref;
1004 int ret;
1005
1006 if (!drm_property_change_valid_get(prop, prop_value, &ref))
1007 return -EINVAL;
1008
1009 switch (obj->type) {
1010 case DRM_MODE_OBJECT_CONNECTOR: {
1011 struct drm_connector *connector = obj_to_connector(obj);
1012 struct drm_connector_state *connector_state;
1013
1014 connector_state = drm_atomic_get_connector_state(state, connector);
1015 if (IS_ERR(connector_state)) {
1016 ret = PTR_ERR(connector_state);
1017 break;
1018 }
1019
1020 ret = drm_atomic_connector_set_property(connector,
1021 connector_state, file_priv,
1022 prop, prop_value);
1023 break;
1024 }
1025 case DRM_MODE_OBJECT_CRTC: {
1026 struct drm_crtc *crtc = obj_to_crtc(obj);
1027 struct drm_crtc_state *crtc_state;
1028
1029 crtc_state = drm_atomic_get_crtc_state(state, crtc);
1030 if (IS_ERR(crtc_state)) {
1031 ret = PTR_ERR(crtc_state);
1032 break;
1033 }
1034
1035 ret = drm_atomic_crtc_set_property(crtc,
1036 crtc_state, prop, prop_value);
1037 break;
1038 }
1039 case DRM_MODE_OBJECT_PLANE: {
1040 struct drm_plane *plane = obj_to_plane(obj);
1041 struct drm_plane_state *plane_state;
1042
1043 plane_state = drm_atomic_get_plane_state(state, plane);
1044 if (IS_ERR(plane_state)) {
1045 ret = PTR_ERR(plane_state);
1046 break;
1047 }
1048
1049 ret = drm_atomic_plane_set_property(plane,
1050 plane_state, file_priv,
1051 prop, prop_value);
1052 break;
1053 }
1054 default:
1055 ret = -EINVAL;
1056 break;
1057 }
1058
1059 drm_property_change_valid_put(prop, ref);
1060 return ret;
1061}
1062
1063
1064
1065
1066
1067
1068
1069
1070
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
1115struct drm_out_fence_state {
1116 s32 __user *out_fence_ptr;
1117 struct sync_file *sync_file;
1118 int fd;
1119};
1120
1121static int setup_out_fence(struct drm_out_fence_state *fence_state,
1122 struct dma_fence *fence)
1123{
1124 fence_state->fd = get_unused_fd_flags(O_CLOEXEC);
1125 if (fence_state->fd < 0)
1126 return fence_state->fd;
1127
1128 if (put_user(fence_state->fd, fence_state->out_fence_ptr))
1129 return -EFAULT;
1130
1131 fence_state->sync_file = sync_file_create(fence);
1132 if (!fence_state->sync_file)
1133 return -ENOMEM;
1134
1135 return 0;
1136}
1137
1138static int prepare_signaling(struct drm_device *dev,
1139 struct drm_atomic_state *state,
1140 struct drm_mode_atomic *arg,
1141 struct drm_file *file_priv,
1142 struct drm_out_fence_state **fence_state,
1143 unsigned int *num_fences)
1144{
1145 struct drm_crtc *crtc;
1146 struct drm_crtc_state *crtc_state;
1147 struct drm_connector *conn;
1148 struct drm_connector_state *conn_state;
1149 int i, c = 0, ret;
1150
1151 if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
1152 return 0;
1153
1154 for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
1155 s32 __user *fence_ptr;
1156
1157 fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc);
1158
1159 if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) {
1160 struct drm_pending_vblank_event *e;
1161
1162 e = create_vblank_event(crtc, arg->user_data);
1163 if (!e)
1164 return -ENOMEM;
1165
1166 crtc_state->event = e;
1167 }
1168
1169 if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
1170 struct drm_pending_vblank_event *e = crtc_state->event;
1171
1172 if (!file_priv)
1173 continue;
1174
1175 ret = drm_event_reserve_init(dev, file_priv, &e->base,
1176 &e->event.base);
1177 if (ret) {
1178 kfree(e);
1179 crtc_state->event = NULL;
1180 return ret;
1181 }
1182 }
1183
1184 if (fence_ptr) {
1185 struct dma_fence *fence;
1186 struct drm_out_fence_state *f;
1187
1188 f = krealloc(*fence_state, sizeof(**fence_state) *
1189 (*num_fences + 1), GFP_KERNEL);
1190 if (!f)
1191 return -ENOMEM;
1192
1193 memset(&f[*num_fences], 0, sizeof(*f));
1194
1195 f[*num_fences].out_fence_ptr = fence_ptr;
1196 *fence_state = f;
1197
1198 fence = drm_crtc_create_fence(crtc);
1199 if (!fence)
1200 return -ENOMEM;
1201
1202 ret = setup_out_fence(&f[(*num_fences)++], fence);
1203 if (ret) {
1204 dma_fence_put(fence);
1205 return ret;
1206 }
1207
1208 crtc_state->event->base.fence = fence;
1209 }
1210
1211 c++;
1212 }
1213
1214 for_each_new_connector_in_state(state, conn, conn_state, i) {
1215 struct drm_writeback_connector *wb_conn;
1216 struct drm_out_fence_state *f;
1217 struct dma_fence *fence;
1218 s32 __user *fence_ptr;
1219
1220 if (!conn_state->writeback_job)
1221 continue;
1222
1223 fence_ptr = get_out_fence_for_connector(state, conn);
1224 if (!fence_ptr)
1225 continue;
1226
1227 f = krealloc(*fence_state, sizeof(**fence_state) *
1228 (*num_fences + 1), GFP_KERNEL);
1229 if (!f)
1230 return -ENOMEM;
1231
1232 memset(&f[*num_fences], 0, sizeof(*f));
1233
1234 f[*num_fences].out_fence_ptr = fence_ptr;
1235 *fence_state = f;
1236
1237 wb_conn = drm_connector_to_writeback(conn);
1238 fence = drm_writeback_get_out_fence(wb_conn);
1239 if (!fence)
1240 return -ENOMEM;
1241
1242 ret = setup_out_fence(&f[(*num_fences)++], fence);
1243 if (ret) {
1244 dma_fence_put(fence);
1245 return ret;
1246 }
1247
1248 conn_state->writeback_job->out_fence = fence;
1249 }
1250
1251
1252
1253
1254
1255 if (c == 0 && (arg->flags & DRM_MODE_PAGE_FLIP_EVENT))
1256 return -EINVAL;
1257
1258 return 0;
1259}
1260
1261static void complete_signaling(struct drm_device *dev,
1262 struct drm_atomic_state *state,
1263 struct drm_out_fence_state *fence_state,
1264 unsigned int num_fences,
1265 bool install_fds)
1266{
1267 struct drm_crtc *crtc;
1268 struct drm_crtc_state *crtc_state;
1269 int i;
1270
1271 if (install_fds) {
1272 for (i = 0; i < num_fences; i++)
1273 fd_install(fence_state[i].fd,
1274 fence_state[i].sync_file->file);
1275
1276 kfree(fence_state);
1277 return;
1278 }
1279
1280 for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
1281 struct drm_pending_vblank_event *event = crtc_state->event;
1282
1283
1284
1285
1286
1287 if (event && (event->base.fence || event->base.file_priv)) {
1288 drm_event_cancel_free(dev, &event->base);
1289 crtc_state->event = NULL;
1290 }
1291 }
1292
1293 if (!fence_state)
1294 return;
1295
1296 for (i = 0; i < num_fences; i++) {
1297 if (fence_state[i].sync_file)
1298 fput(fence_state[i].sync_file->file);
1299 if (fence_state[i].fd >= 0)
1300 put_unused_fd(fence_state[i].fd);
1301
1302
1303 if (fence_state[i].out_fence_ptr &&
1304 put_user(-1, fence_state[i].out_fence_ptr))
1305 drm_dbg_atomic(dev, "Couldn't clear out_fence_ptr\n");
1306 }
1307
1308 kfree(fence_state);
1309}
1310
1311int drm_mode_atomic_ioctl(struct drm_device *dev,
1312 void *data, struct drm_file *file_priv)
1313{
1314 struct drm_mode_atomic *arg = data;
1315 uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
1316 uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
1317 uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
1318 uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
1319 unsigned int copied_objs, copied_props;
1320 struct drm_atomic_state *state;
1321 struct drm_modeset_acquire_ctx ctx;
1322 struct drm_out_fence_state *fence_state;
1323 int ret = 0;
1324 unsigned int i, j, num_fences;
1325 struct drm_printer p = drm_info_printer(dev->dev);
1326
1327
1328 if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
1329 return -EOPNOTSUPP;
1330
1331
1332
1333
1334
1335 if (!file_priv->atomic) {
1336 drm_dbg_atomic(dev,
1337 "commit failed: atomic cap not enabled\n");
1338 return -EINVAL;
1339 }
1340
1341 if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS) {
1342 drm_dbg_atomic(dev, "commit failed: invalid flag\n");
1343 return -EINVAL;
1344 }
1345
1346 if (arg->reserved) {
1347 drm_dbg_atomic(dev, "commit failed: reserved field set\n");
1348 return -EINVAL;
1349 }
1350
1351 if (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) {
1352 drm_dbg_atomic(dev,
1353 "commit failed: invalid flag DRM_MODE_PAGE_FLIP_ASYNC\n");
1354 return -EINVAL;
1355 }
1356
1357
1358 if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
1359 (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) {
1360 drm_dbg_atomic(dev,
1361 "commit failed: page-flip event requested with test-only commit\n");
1362 return -EINVAL;
1363 }
1364
1365 state = drm_atomic_state_alloc(dev);
1366 if (!state)
1367 return -ENOMEM;
1368
1369 drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
1370 state->acquire_ctx = &ctx;
1371 state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);
1372
1373retry:
1374 copied_objs = 0;
1375 copied_props = 0;
1376 fence_state = NULL;
1377 num_fences = 0;
1378
1379 for (i = 0; i < arg->count_objs; i++) {
1380 uint32_t obj_id, count_props;
1381 struct drm_mode_object *obj;
1382
1383 if (get_user(obj_id, objs_ptr + copied_objs)) {
1384 ret = -EFAULT;
1385 goto out;
1386 }
1387
1388 obj = drm_mode_object_find(dev, file_priv, obj_id, DRM_MODE_OBJECT_ANY);
1389 if (!obj) {
1390 ret = -ENOENT;
1391 goto out;
1392 }
1393
1394 if (!obj->properties) {
1395 drm_mode_object_put(obj);
1396 ret = -ENOENT;
1397 goto out;
1398 }
1399
1400 if (get_user(count_props, count_props_ptr + copied_objs)) {
1401 drm_mode_object_put(obj);
1402 ret = -EFAULT;
1403 goto out;
1404 }
1405
1406 copied_objs++;
1407
1408 for (j = 0; j < count_props; j++) {
1409 uint32_t prop_id;
1410 uint64_t prop_value;
1411 struct drm_property *prop;
1412
1413 if (get_user(prop_id, props_ptr + copied_props)) {
1414 drm_mode_object_put(obj);
1415 ret = -EFAULT;
1416 goto out;
1417 }
1418
1419 prop = drm_mode_obj_find_prop_id(obj, prop_id);
1420 if (!prop) {
1421 drm_mode_object_put(obj);
1422 ret = -ENOENT;
1423 goto out;
1424 }
1425
1426 if (copy_from_user(&prop_value,
1427 prop_values_ptr + copied_props,
1428 sizeof(prop_value))) {
1429 drm_mode_object_put(obj);
1430 ret = -EFAULT;
1431 goto out;
1432 }
1433
1434 ret = drm_atomic_set_property(state, file_priv,
1435 obj, prop, prop_value);
1436 if (ret) {
1437 drm_mode_object_put(obj);
1438 goto out;
1439 }
1440
1441 copied_props++;
1442 }
1443
1444 drm_mode_object_put(obj);
1445 }
1446
1447 ret = prepare_signaling(dev, state, arg, file_priv, &fence_state,
1448 &num_fences);
1449 if (ret)
1450 goto out;
1451
1452 if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) {
1453 ret = drm_atomic_check_only(state);
1454 } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) {
1455 ret = drm_atomic_nonblocking_commit(state);
1456 } else {
1457 if (drm_debug_enabled(DRM_UT_STATE))
1458 drm_atomic_print_new_state(state, &p);
1459
1460 ret = drm_atomic_commit(state);
1461 }
1462
1463out:
1464 complete_signaling(dev, state, fence_state, num_fences, !ret);
1465
1466 if (ret == -EDEADLK) {
1467 drm_atomic_state_clear(state);
1468 ret = drm_modeset_backoff(&ctx);
1469 if (!ret)
1470 goto retry;
1471 }
1472
1473 drm_atomic_state_put(state);
1474
1475 drm_modeset_drop_locks(&ctx);
1476 drm_modeset_acquire_fini(&ctx);
1477
1478 return ret;
1479}
1480