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 = drm_atomic_crtc_effectively_active(state);
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 bool replaced = false;
680 int ret;
681
682 if (property == config->prop_crtc_id) {
683 struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val);
684 if (val && !crtc)
685 return -EACCES;
686 return drm_atomic_set_crtc_for_connector(state, crtc);
687 } else if (property == config->dpms_property) {
688
689
690
691
692 return -EINVAL;
693 } else if (property == config->tv_select_subconnector_property) {
694 state->tv.subconnector = val;
695 } else if (property == config->tv_left_margin_property) {
696 state->tv.margins.left = val;
697 } else if (property == config->tv_right_margin_property) {
698 state->tv.margins.right = val;
699 } else if (property == config->tv_top_margin_property) {
700 state->tv.margins.top = val;
701 } else if (property == config->tv_bottom_margin_property) {
702 state->tv.margins.bottom = val;
703 } else if (property == config->tv_mode_property) {
704 state->tv.mode = val;
705 } else if (property == config->tv_brightness_property) {
706 state->tv.brightness = val;
707 } else if (property == config->tv_contrast_property) {
708 state->tv.contrast = val;
709 } else if (property == config->tv_flicker_reduction_property) {
710 state->tv.flicker_reduction = val;
711 } else if (property == config->tv_overscan_property) {
712 state->tv.overscan = val;
713 } else if (property == config->tv_saturation_property) {
714 state->tv.saturation = val;
715 } else if (property == config->tv_hue_property) {
716 state->tv.hue = val;
717 } else if (property == config->link_status_property) {
718
719
720
721
722
723
724
725
726
727
728
729 if (state->link_status != DRM_LINK_STATUS_GOOD)
730 state->link_status = val;
731 } else if (property == config->hdr_output_metadata_property) {
732 ret = drm_atomic_replace_property_blob_from_id(dev,
733 &state->hdr_output_metadata,
734 val,
735 sizeof(struct hdr_output_metadata), -1,
736 &replaced);
737 return ret;
738 } else if (property == config->aspect_ratio_property) {
739 state->picture_aspect_ratio = val;
740 } else if (property == config->content_type_property) {
741 state->content_type = val;
742 } else if (property == connector->scaling_mode_property) {
743 state->scaling_mode = val;
744 } else if (property == config->content_protection_property) {
745 if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
746 DRM_DEBUG_KMS("only drivers can set CP Enabled\n");
747 return -EINVAL;
748 }
749 state->content_protection = val;
750 } else if (property == config->hdcp_content_type_property) {
751 state->hdcp_content_type = val;
752 } else if (property == connector->colorspace_property) {
753 state->colorspace = val;
754 } else if (property == config->writeback_fb_id_property) {
755 struct drm_framebuffer *fb;
756 int ret;
757 fb = drm_framebuffer_lookup(dev, file_priv, val);
758 ret = drm_atomic_set_writeback_fb_for_connector(state, fb);
759 if (fb)
760 drm_framebuffer_put(fb);
761 return ret;
762 } else if (property == config->writeback_out_fence_ptr_property) {
763 s32 __user *fence_ptr = u64_to_user_ptr(val);
764
765 return set_out_fence_for_connector(state->state, connector,
766 fence_ptr);
767 } else if (property == connector->max_bpc_property) {
768 state->max_requested_bpc = val;
769 } else if (connector->funcs->atomic_set_property) {
770 return connector->funcs->atomic_set_property(connector,
771 state, property, val);
772 } else {
773 DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] unknown property [PROP:%d:%s]]\n",
774 connector->base.id, connector->name,
775 property->base.id, property->name);
776 return -EINVAL;
777 }
778
779 return 0;
780}
781
782static int
783drm_atomic_connector_get_property(struct drm_connector *connector,
784 const struct drm_connector_state *state,
785 struct drm_property *property, uint64_t *val)
786{
787 struct drm_device *dev = connector->dev;
788 struct drm_mode_config *config = &dev->mode_config;
789
790 if (property == config->prop_crtc_id) {
791 *val = (state->crtc) ? state->crtc->base.id : 0;
792 } else if (property == config->dpms_property) {
793 if (state->crtc && state->crtc->state->self_refresh_active)
794 *val = DRM_MODE_DPMS_ON;
795 else
796 *val = connector->dpms;
797 } else if (property == config->tv_select_subconnector_property) {
798 *val = state->tv.subconnector;
799 } else if (property == config->tv_left_margin_property) {
800 *val = state->tv.margins.left;
801 } else if (property == config->tv_right_margin_property) {
802 *val = state->tv.margins.right;
803 } else if (property == config->tv_top_margin_property) {
804 *val = state->tv.margins.top;
805 } else if (property == config->tv_bottom_margin_property) {
806 *val = state->tv.margins.bottom;
807 } else if (property == config->tv_mode_property) {
808 *val = state->tv.mode;
809 } else if (property == config->tv_brightness_property) {
810 *val = state->tv.brightness;
811 } else if (property == config->tv_contrast_property) {
812 *val = state->tv.contrast;
813 } else if (property == config->tv_flicker_reduction_property) {
814 *val = state->tv.flicker_reduction;
815 } else if (property == config->tv_overscan_property) {
816 *val = state->tv.overscan;
817 } else if (property == config->tv_saturation_property) {
818 *val = state->tv.saturation;
819 } else if (property == config->tv_hue_property) {
820 *val = state->tv.hue;
821 } else if (property == config->link_status_property) {
822 *val = state->link_status;
823 } else if (property == config->aspect_ratio_property) {
824 *val = state->picture_aspect_ratio;
825 } else if (property == config->content_type_property) {
826 *val = state->content_type;
827 } else if (property == connector->colorspace_property) {
828 *val = state->colorspace;
829 } else if (property == connector->scaling_mode_property) {
830 *val = state->scaling_mode;
831 } else if (property == config->hdr_output_metadata_property) {
832 *val = state->hdr_output_metadata ?
833 state->hdr_output_metadata->base.id : 0;
834 } else if (property == config->content_protection_property) {
835 *val = state->content_protection;
836 } else if (property == config->hdcp_content_type_property) {
837 *val = state->hdcp_content_type;
838 } else if (property == config->writeback_fb_id_property) {
839
840 *val = 0;
841 } else if (property == config->writeback_out_fence_ptr_property) {
842 *val = 0;
843 } else if (property == connector->max_bpc_property) {
844 *val = state->max_requested_bpc;
845 } else if (connector->funcs->atomic_get_property) {
846 return connector->funcs->atomic_get_property(connector,
847 state, property, val);
848 } else {
849 return -EINVAL;
850 }
851
852 return 0;
853}
854
855int drm_atomic_get_property(struct drm_mode_object *obj,
856 struct drm_property *property, uint64_t *val)
857{
858 struct drm_device *dev = property->dev;
859 int ret;
860
861 switch (obj->type) {
862 case DRM_MODE_OBJECT_CONNECTOR: {
863 struct drm_connector *connector = obj_to_connector(obj);
864 WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
865 ret = drm_atomic_connector_get_property(connector,
866 connector->state, property, val);
867 break;
868 }
869 case DRM_MODE_OBJECT_CRTC: {
870 struct drm_crtc *crtc = obj_to_crtc(obj);
871 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
872 ret = drm_atomic_crtc_get_property(crtc,
873 crtc->state, property, val);
874 break;
875 }
876 case DRM_MODE_OBJECT_PLANE: {
877 struct drm_plane *plane = obj_to_plane(obj);
878 WARN_ON(!drm_modeset_is_locked(&plane->mutex));
879 ret = drm_atomic_plane_get_property(plane,
880 plane->state, property, val);
881 break;
882 }
883 default:
884 ret = -EINVAL;
885 break;
886 }
887
888 return ret;
889}
890
891
892
893
894
895static struct drm_pending_vblank_event *create_vblank_event(
896 struct drm_crtc *crtc, uint64_t user_data)
897{
898 struct drm_pending_vblank_event *e = NULL;
899
900 e = kzalloc(sizeof *e, GFP_KERNEL);
901 if (!e)
902 return NULL;
903
904 e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
905 e->event.base.length = sizeof(e->event);
906 e->event.vbl.crtc_id = crtc->base.id;
907 e->event.vbl.user_data = user_data;
908
909 return e;
910}
911
912int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state,
913 struct drm_connector *connector,
914 int mode)
915{
916 struct drm_connector *tmp_connector;
917 struct drm_connector_state *new_conn_state;
918 struct drm_crtc *crtc;
919 struct drm_crtc_state *crtc_state;
920 int i, ret, old_mode = connector->dpms;
921 bool active = false;
922
923 ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
924 state->acquire_ctx);
925 if (ret)
926 return ret;
927
928 if (mode != DRM_MODE_DPMS_ON)
929 mode = DRM_MODE_DPMS_OFF;
930 connector->dpms = mode;
931
932 crtc = connector->state->crtc;
933 if (!crtc)
934 goto out;
935 ret = drm_atomic_add_affected_connectors(state, crtc);
936 if (ret)
937 goto out;
938
939 crtc_state = drm_atomic_get_crtc_state(state, crtc);
940 if (IS_ERR(crtc_state)) {
941 ret = PTR_ERR(crtc_state);
942 goto out;
943 }
944
945 for_each_new_connector_in_state(state, tmp_connector, new_conn_state, i) {
946 if (new_conn_state->crtc != crtc)
947 continue;
948 if (tmp_connector->dpms == DRM_MODE_DPMS_ON) {
949 active = true;
950 break;
951 }
952 }
953
954 crtc_state->active = active;
955 ret = drm_atomic_commit(state);
956out:
957 if (ret != 0)
958 connector->dpms = old_mode;
959 return ret;
960}
961
962int drm_atomic_set_property(struct drm_atomic_state *state,
963 struct drm_file *file_priv,
964 struct drm_mode_object *obj,
965 struct drm_property *prop,
966 uint64_t prop_value)
967{
968 struct drm_mode_object *ref;
969 int ret;
970
971 if (!drm_property_change_valid_get(prop, prop_value, &ref))
972 return -EINVAL;
973
974 switch (obj->type) {
975 case DRM_MODE_OBJECT_CONNECTOR: {
976 struct drm_connector *connector = obj_to_connector(obj);
977 struct drm_connector_state *connector_state;
978
979 connector_state = drm_atomic_get_connector_state(state, connector);
980 if (IS_ERR(connector_state)) {
981 ret = PTR_ERR(connector_state);
982 break;
983 }
984
985 ret = drm_atomic_connector_set_property(connector,
986 connector_state, file_priv,
987 prop, prop_value);
988 break;
989 }
990 case DRM_MODE_OBJECT_CRTC: {
991 struct drm_crtc *crtc = obj_to_crtc(obj);
992 struct drm_crtc_state *crtc_state;
993
994 crtc_state = drm_atomic_get_crtc_state(state, crtc);
995 if (IS_ERR(crtc_state)) {
996 ret = PTR_ERR(crtc_state);
997 break;
998 }
999
1000 ret = drm_atomic_crtc_set_property(crtc,
1001 crtc_state, prop, prop_value);
1002 break;
1003 }
1004 case DRM_MODE_OBJECT_PLANE: {
1005 struct drm_plane *plane = obj_to_plane(obj);
1006 struct drm_plane_state *plane_state;
1007
1008 plane_state = drm_atomic_get_plane_state(state, plane);
1009 if (IS_ERR(plane_state)) {
1010 ret = PTR_ERR(plane_state);
1011 break;
1012 }
1013
1014 ret = drm_atomic_plane_set_property(plane,
1015 plane_state, file_priv,
1016 prop, prop_value);
1017 break;
1018 }
1019 default:
1020 ret = -EINVAL;
1021 break;
1022 }
1023
1024 drm_property_change_valid_put(prop, ref);
1025 return ret;
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
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080struct drm_out_fence_state {
1081 s32 __user *out_fence_ptr;
1082 struct sync_file *sync_file;
1083 int fd;
1084};
1085
1086static int setup_out_fence(struct drm_out_fence_state *fence_state,
1087 struct dma_fence *fence)
1088{
1089 fence_state->fd = get_unused_fd_flags(O_CLOEXEC);
1090 if (fence_state->fd < 0)
1091 return fence_state->fd;
1092
1093 if (put_user(fence_state->fd, fence_state->out_fence_ptr))
1094 return -EFAULT;
1095
1096 fence_state->sync_file = sync_file_create(fence);
1097 if (!fence_state->sync_file)
1098 return -ENOMEM;
1099
1100 return 0;
1101}
1102
1103static int prepare_signaling(struct drm_device *dev,
1104 struct drm_atomic_state *state,
1105 struct drm_mode_atomic *arg,
1106 struct drm_file *file_priv,
1107 struct drm_out_fence_state **fence_state,
1108 unsigned int *num_fences)
1109{
1110 struct drm_crtc *crtc;
1111 struct drm_crtc_state *crtc_state;
1112 struct drm_connector *conn;
1113 struct drm_connector_state *conn_state;
1114 int i, c = 0, ret;
1115
1116 if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
1117 return 0;
1118
1119 for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
1120 s32 __user *fence_ptr;
1121
1122 fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc);
1123
1124 if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) {
1125 struct drm_pending_vblank_event *e;
1126
1127 e = create_vblank_event(crtc, arg->user_data);
1128 if (!e)
1129 return -ENOMEM;
1130
1131 crtc_state->event = e;
1132 }
1133
1134 if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
1135 struct drm_pending_vblank_event *e = crtc_state->event;
1136
1137 if (!file_priv)
1138 continue;
1139
1140 ret = drm_event_reserve_init(dev, file_priv, &e->base,
1141 &e->event.base);
1142 if (ret) {
1143 kfree(e);
1144 crtc_state->event = NULL;
1145 return ret;
1146 }
1147 }
1148
1149 if (fence_ptr) {
1150 struct dma_fence *fence;
1151 struct drm_out_fence_state *f;
1152
1153 f = krealloc(*fence_state, sizeof(**fence_state) *
1154 (*num_fences + 1), GFP_KERNEL);
1155 if (!f)
1156 return -ENOMEM;
1157
1158 memset(&f[*num_fences], 0, sizeof(*f));
1159
1160 f[*num_fences].out_fence_ptr = fence_ptr;
1161 *fence_state = f;
1162
1163 fence = drm_crtc_create_fence(crtc);
1164 if (!fence)
1165 return -ENOMEM;
1166
1167 ret = setup_out_fence(&f[(*num_fences)++], fence);
1168 if (ret) {
1169 dma_fence_put(fence);
1170 return ret;
1171 }
1172
1173 crtc_state->event->base.fence = fence;
1174 }
1175
1176 c++;
1177 }
1178
1179 for_each_new_connector_in_state(state, conn, conn_state, i) {
1180 struct drm_writeback_connector *wb_conn;
1181 struct drm_out_fence_state *f;
1182 struct dma_fence *fence;
1183 s32 __user *fence_ptr;
1184
1185 if (!conn_state->writeback_job)
1186 continue;
1187
1188 fence_ptr = get_out_fence_for_connector(state, conn);
1189 if (!fence_ptr)
1190 continue;
1191
1192 f = krealloc(*fence_state, sizeof(**fence_state) *
1193 (*num_fences + 1), GFP_KERNEL);
1194 if (!f)
1195 return -ENOMEM;
1196
1197 memset(&f[*num_fences], 0, sizeof(*f));
1198
1199 f[*num_fences].out_fence_ptr = fence_ptr;
1200 *fence_state = f;
1201
1202 wb_conn = drm_connector_to_writeback(conn);
1203 fence = drm_writeback_get_out_fence(wb_conn);
1204 if (!fence)
1205 return -ENOMEM;
1206
1207 ret = setup_out_fence(&f[(*num_fences)++], fence);
1208 if (ret) {
1209 dma_fence_put(fence);
1210 return ret;
1211 }
1212
1213 conn_state->writeback_job->out_fence = fence;
1214 }
1215
1216
1217
1218
1219
1220 if (c == 0 && (arg->flags & DRM_MODE_PAGE_FLIP_EVENT))
1221 return -EINVAL;
1222
1223 return 0;
1224}
1225
1226static void complete_signaling(struct drm_device *dev,
1227 struct drm_atomic_state *state,
1228 struct drm_out_fence_state *fence_state,
1229 unsigned int num_fences,
1230 bool install_fds)
1231{
1232 struct drm_crtc *crtc;
1233 struct drm_crtc_state *crtc_state;
1234 int i;
1235
1236 if (install_fds) {
1237 for (i = 0; i < num_fences; i++)
1238 fd_install(fence_state[i].fd,
1239 fence_state[i].sync_file->file);
1240
1241 kfree(fence_state);
1242 return;
1243 }
1244
1245 for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
1246 struct drm_pending_vblank_event *event = crtc_state->event;
1247
1248
1249
1250
1251
1252 if (event && (event->base.fence || event->base.file_priv)) {
1253 drm_event_cancel_free(dev, &event->base);
1254 crtc_state->event = NULL;
1255 }
1256 }
1257
1258 if (!fence_state)
1259 return;
1260
1261 for (i = 0; i < num_fences; i++) {
1262 if (fence_state[i].sync_file)
1263 fput(fence_state[i].sync_file->file);
1264 if (fence_state[i].fd >= 0)
1265 put_unused_fd(fence_state[i].fd);
1266
1267
1268 if (fence_state[i].out_fence_ptr &&
1269 put_user(-1, fence_state[i].out_fence_ptr))
1270 DRM_DEBUG_ATOMIC("Couldn't clear out_fence_ptr\n");
1271 }
1272
1273 kfree(fence_state);
1274}
1275
1276int drm_mode_atomic_ioctl(struct drm_device *dev,
1277 void *data, struct drm_file *file_priv)
1278{
1279 struct drm_mode_atomic *arg = data;
1280 uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
1281 uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
1282 uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
1283 uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
1284 unsigned int copied_objs, copied_props;
1285 struct drm_atomic_state *state;
1286 struct drm_modeset_acquire_ctx ctx;
1287 struct drm_out_fence_state *fence_state;
1288 int ret = 0;
1289 unsigned int i, j, num_fences;
1290
1291
1292 if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
1293 return -EOPNOTSUPP;
1294
1295
1296
1297
1298
1299 if (!file_priv->atomic)
1300 return -EINVAL;
1301
1302 if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS)
1303 return -EINVAL;
1304
1305 if (arg->reserved)
1306 return -EINVAL;
1307
1308 if (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC)
1309 return -EINVAL;
1310
1311
1312 if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
1313 (arg->flags & DRM_MODE_PAGE_FLIP_EVENT))
1314 return -EINVAL;
1315
1316 state = drm_atomic_state_alloc(dev);
1317 if (!state)
1318 return -ENOMEM;
1319
1320 drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
1321 state->acquire_ctx = &ctx;
1322 state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);
1323
1324retry:
1325 copied_objs = 0;
1326 copied_props = 0;
1327 fence_state = NULL;
1328 num_fences = 0;
1329
1330 for (i = 0; i < arg->count_objs; i++) {
1331 uint32_t obj_id, count_props;
1332 struct drm_mode_object *obj;
1333
1334 if (get_user(obj_id, objs_ptr + copied_objs)) {
1335 ret = -EFAULT;
1336 goto out;
1337 }
1338
1339 obj = drm_mode_object_find(dev, file_priv, obj_id, DRM_MODE_OBJECT_ANY);
1340 if (!obj) {
1341 ret = -ENOENT;
1342 goto out;
1343 }
1344
1345 if (!obj->properties) {
1346 drm_mode_object_put(obj);
1347 ret = -ENOENT;
1348 goto out;
1349 }
1350
1351 if (get_user(count_props, count_props_ptr + copied_objs)) {
1352 drm_mode_object_put(obj);
1353 ret = -EFAULT;
1354 goto out;
1355 }
1356
1357 copied_objs++;
1358
1359 for (j = 0; j < count_props; j++) {
1360 uint32_t prop_id;
1361 uint64_t prop_value;
1362 struct drm_property *prop;
1363
1364 if (get_user(prop_id, props_ptr + copied_props)) {
1365 drm_mode_object_put(obj);
1366 ret = -EFAULT;
1367 goto out;
1368 }
1369
1370 prop = drm_mode_obj_find_prop_id(obj, prop_id);
1371 if (!prop) {
1372 drm_mode_object_put(obj);
1373 ret = -ENOENT;
1374 goto out;
1375 }
1376
1377 if (copy_from_user(&prop_value,
1378 prop_values_ptr + copied_props,
1379 sizeof(prop_value))) {
1380 drm_mode_object_put(obj);
1381 ret = -EFAULT;
1382 goto out;
1383 }
1384
1385 ret = drm_atomic_set_property(state, file_priv,
1386 obj, prop, prop_value);
1387 if (ret) {
1388 drm_mode_object_put(obj);
1389 goto out;
1390 }
1391
1392 copied_props++;
1393 }
1394
1395 drm_mode_object_put(obj);
1396 }
1397
1398 ret = prepare_signaling(dev, state, arg, file_priv, &fence_state,
1399 &num_fences);
1400 if (ret)
1401 goto out;
1402
1403 if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) {
1404 ret = drm_atomic_check_only(state);
1405 } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) {
1406 ret = drm_atomic_nonblocking_commit(state);
1407 } else {
1408 if (drm_debug_enabled(DRM_UT_STATE))
1409 drm_atomic_print_state(state);
1410
1411 ret = drm_atomic_commit(state);
1412 }
1413
1414out:
1415 complete_signaling(dev, state, fence_state, num_fences, !ret);
1416
1417 if (ret == -EDEADLK) {
1418 drm_atomic_state_clear(state);
1419 ret = drm_modeset_backoff(&ctx);
1420 if (!ret)
1421 goto retry;
1422 }
1423
1424 drm_atomic_state_put(state);
1425
1426 drm_modeset_drop_locks(&ctx);
1427 drm_modeset_acquire_fini(&ctx);
1428
1429 return ret;
1430}
1431