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