diff options
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/drm_atomic.c | 730 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_atomic_helper.c | 106 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 345 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc_internal.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_drv.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_ioctl.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_plane_helper.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_atomic.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.h | 2 |
12 files changed, 1083 insertions, 150 deletions
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index ff5f034cc405..1e38dfc8e462 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c | |||
@@ -56,6 +56,11 @@ drm_atomic_state_alloc(struct drm_device *dev) | |||
56 | if (!state) | 56 | if (!state) |
57 | return NULL; | 57 | return NULL; |
58 | 58 | ||
59 | /* TODO legacy paths should maybe do a better job about | ||
60 | * setting this appropriately? | ||
61 | */ | ||
62 | state->allow_modeset = true; | ||
63 | |||
59 | state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector); | 64 | state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector); |
60 | 65 | ||
61 | state->crtcs = kcalloc(dev->mode_config.num_crtc, | 66 | state->crtcs = kcalloc(dev->mode_config.num_crtc, |
@@ -217,6 +222,70 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, | |||
217 | EXPORT_SYMBOL(drm_atomic_get_crtc_state); | 222 | EXPORT_SYMBOL(drm_atomic_get_crtc_state); |
218 | 223 | ||
219 | /** | 224 | /** |
225 | * drm_atomic_crtc_set_property - set property on CRTC | ||
226 | * @crtc: the drm CRTC to set a property on | ||
227 | * @state: the state object to update with the new property value | ||
228 | * @property: the property to set | ||
229 | * @val: the new property value | ||
230 | * | ||
231 | * Use this instead of calling crtc->atomic_set_property directly. | ||
232 | * This function handles generic/core properties and calls out to | ||
233 | * driver's ->atomic_set_property() for driver properties. To ensure | ||
234 | * consistent behavior you must call this function rather than the | ||
235 | * driver hook directly. | ||
236 | * | ||
237 | * RETURNS: | ||
238 | * Zero on success, error code on failure | ||
239 | */ | ||
240 | int drm_atomic_crtc_set_property(struct drm_crtc *crtc, | ||
241 | struct drm_crtc_state *state, struct drm_property *property, | ||
242 | uint64_t val) | ||
243 | { | ||
244 | if (crtc->funcs->atomic_set_property) | ||
245 | return crtc->funcs->atomic_set_property(crtc, state, property, val); | ||
246 | return -EINVAL; | ||
247 | } | ||
248 | EXPORT_SYMBOL(drm_atomic_crtc_set_property); | ||
249 | |||
250 | /* | ||
251 | * This function handles generic/core properties and calls out to | ||
252 | * driver's ->atomic_get_property() for driver properties. To ensure | ||
253 | * consistent behavior you must call this function rather than the | ||
254 | * driver hook directly. | ||
255 | */ | ||
256 | int drm_atomic_crtc_get_property(struct drm_crtc *crtc, | ||
257 | const struct drm_crtc_state *state, | ||
258 | struct drm_property *property, uint64_t *val) | ||
259 | { | ||
260 | if (crtc->funcs->atomic_get_property) | ||
261 | return crtc->funcs->atomic_get_property(crtc, state, property, val); | ||
262 | return -EINVAL; | ||
263 | } | ||
264 | |||
265 | /** | ||
266 | * drm_atomic_crtc_check - check crtc state | ||
267 | * @crtc: crtc to check | ||
268 | * @state: crtc state to check | ||
269 | * | ||
270 | * Provides core sanity checks for crtc state. | ||
271 | * | ||
272 | * RETURNS: | ||
273 | * Zero on success, error code on failure | ||
274 | */ | ||
275 | static int drm_atomic_crtc_check(struct drm_crtc *crtc, | ||
276 | struct drm_crtc_state *state) | ||
277 | { | ||
278 | /* NOTE: we explicitly don't enforce constraints such as primary | ||
279 | * layer covering entire screen, since that is something we want | ||
280 | * to allow (on hw that supports it). For hw that does not, it | ||
281 | * should be checked in driver's crtc->atomic_check() vfunc. | ||
282 | * | ||
283 | * TODO: Add generic modeset state checks once we support those. | ||
284 | */ | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | /** | ||
220 | * drm_atomic_get_plane_state - get plane state | 289 | * drm_atomic_get_plane_state - get plane state |
221 | * @state: global atomic state object | 290 | * @state: global atomic state object |
222 | * @plane: plane to get state object for | 291 | * @plane: plane to get state object for |
@@ -272,6 +341,183 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state, | |||
272 | EXPORT_SYMBOL(drm_atomic_get_plane_state); | 341 | EXPORT_SYMBOL(drm_atomic_get_plane_state); |
273 | 342 | ||
274 | /** | 343 | /** |
344 | * drm_atomic_plane_set_property - set property on plane | ||
345 | * @plane: the drm plane to set a property on | ||
346 | * @state: the state object to update with the new property value | ||
347 | * @property: the property to set | ||
348 | * @val: the new property value | ||
349 | * | ||
350 | * Use this instead of calling plane->atomic_set_property directly. | ||
351 | * This function handles generic/core properties and calls out to | ||
352 | * driver's ->atomic_set_property() for driver properties. To ensure | ||
353 | * consistent behavior you must call this function rather than the | ||
354 | * driver hook directly. | ||
355 | * | ||
356 | * RETURNS: | ||
357 | * Zero on success, error code on failure | ||
358 | */ | ||
359 | int drm_atomic_plane_set_property(struct drm_plane *plane, | ||
360 | struct drm_plane_state *state, struct drm_property *property, | ||
361 | uint64_t val) | ||
362 | { | ||
363 | struct drm_device *dev = plane->dev; | ||
364 | struct drm_mode_config *config = &dev->mode_config; | ||
365 | |||
366 | if (property == config->prop_fb_id) { | ||
367 | struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, val); | ||
368 | drm_atomic_set_fb_for_plane(state, fb); | ||
369 | if (fb) | ||
370 | drm_framebuffer_unreference(fb); | ||
371 | } else if (property == config->prop_crtc_id) { | ||
372 | struct drm_crtc *crtc = drm_crtc_find(dev, val); | ||
373 | return drm_atomic_set_crtc_for_plane(state, crtc); | ||
374 | } else if (property == config->prop_crtc_x) { | ||
375 | state->crtc_x = U642I64(val); | ||
376 | } else if (property == config->prop_crtc_y) { | ||
377 | state->crtc_y = U642I64(val); | ||
378 | } else if (property == config->prop_crtc_w) { | ||
379 | state->crtc_w = val; | ||
380 | } else if (property == config->prop_crtc_h) { | ||
381 | state->crtc_h = val; | ||
382 | } else if (property == config->prop_src_x) { | ||
383 | state->src_x = val; | ||
384 | } else if (property == config->prop_src_y) { | ||
385 | state->src_y = val; | ||
386 | } else if (property == config->prop_src_w) { | ||
387 | state->src_w = val; | ||
388 | } else if (property == config->prop_src_h) { | ||
389 | state->src_h = val; | ||
390 | } else if (plane->funcs->atomic_set_property) { | ||
391 | return plane->funcs->atomic_set_property(plane, state, | ||
392 | property, val); | ||
393 | } else { | ||
394 | return -EINVAL; | ||
395 | } | ||
396 | |||
397 | return 0; | ||
398 | } | ||
399 | EXPORT_SYMBOL(drm_atomic_plane_set_property); | ||
400 | |||
401 | /* | ||
402 | * This function handles generic/core properties and calls out to | ||
403 | * driver's ->atomic_get_property() for driver properties. To ensure | ||
404 | * consistent behavior you must call this function rather than the | ||
405 | * driver hook directly. | ||
406 | */ | ||
407 | static int | ||
408 | drm_atomic_plane_get_property(struct drm_plane *plane, | ||
409 | const struct drm_plane_state *state, | ||
410 | struct drm_property *property, uint64_t *val) | ||
411 | { | ||
412 | struct drm_device *dev = plane->dev; | ||
413 | struct drm_mode_config *config = &dev->mode_config; | ||
414 | |||
415 | if (property == config->prop_fb_id) { | ||
416 | *val = (state->fb) ? state->fb->base.id : 0; | ||
417 | } else if (property == config->prop_crtc_id) { | ||
418 | *val = (state->crtc) ? state->crtc->base.id : 0; | ||
419 | } else if (property == config->prop_crtc_x) { | ||
420 | *val = I642U64(state->crtc_x); | ||
421 | } else if (property == config->prop_crtc_y) { | ||
422 | *val = I642U64(state->crtc_y); | ||
423 | } else if (property == config->prop_crtc_w) { | ||
424 | *val = state->crtc_w; | ||
425 | } else if (property == config->prop_crtc_h) { | ||
426 | *val = state->crtc_h; | ||
427 | } else if (property == config->prop_src_x) { | ||
428 | *val = state->src_x; | ||
429 | } else if (property == config->prop_src_y) { | ||
430 | *val = state->src_y; | ||
431 | } else if (property == config->prop_src_w) { | ||
432 | *val = state->src_w; | ||
433 | } else if (property == config->prop_src_h) { | ||
434 | *val = state->src_h; | ||
435 | } else if (plane->funcs->atomic_get_property) { | ||
436 | return plane->funcs->atomic_get_property(plane, state, property, val); | ||
437 | } else { | ||
438 | return -EINVAL; | ||
439 | } | ||
440 | |||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | /** | ||
445 | * drm_atomic_plane_check - check plane state | ||
446 | * @plane: plane to check | ||
447 | * @state: plane state to check | ||
448 | * | ||
449 | * Provides core sanity checks for plane state. | ||
450 | * | ||
451 | * RETURNS: | ||
452 | * Zero on success, error code on failure | ||
453 | */ | ||
454 | static int drm_atomic_plane_check(struct drm_plane *plane, | ||
455 | struct drm_plane_state *state) | ||
456 | { | ||
457 | unsigned int fb_width, fb_height; | ||
458 | unsigned int i; | ||
459 | |||
460 | /* either *both* CRTC and FB must be set, or neither */ | ||
461 | if (WARN_ON(state->crtc && !state->fb)) { | ||
462 | DRM_DEBUG_KMS("CRTC set but no FB\n"); | ||
463 | return -EINVAL; | ||
464 | } else if (WARN_ON(state->fb && !state->crtc)) { | ||
465 | DRM_DEBUG_KMS("FB set but no CRTC\n"); | ||
466 | return -EINVAL; | ||
467 | } | ||
468 | |||
469 | /* if disabled, we don't care about the rest of the state: */ | ||
470 | if (!state->crtc) | ||
471 | return 0; | ||
472 | |||
473 | /* Check whether this plane is usable on this CRTC */ | ||
474 | if (!(plane->possible_crtcs & drm_crtc_mask(state->crtc))) { | ||
475 | DRM_DEBUG_KMS("Invalid crtc for plane\n"); | ||
476 | return -EINVAL; | ||
477 | } | ||
478 | |||
479 | /* Check whether this plane supports the fb pixel format. */ | ||
480 | for (i = 0; i < plane->format_count; i++) | ||
481 | if (state->fb->pixel_format == plane->format_types[i]) | ||
482 | break; | ||
483 | if (i == plane->format_count) { | ||
484 | DRM_DEBUG_KMS("Invalid pixel format %s\n", | ||
485 | drm_get_format_name(state->fb->pixel_format)); | ||
486 | return -EINVAL; | ||
487 | } | ||
488 | |||
489 | /* Give drivers some help against integer overflows */ | ||
490 | if (state->crtc_w > INT_MAX || | ||
491 | state->crtc_x > INT_MAX - (int32_t) state->crtc_w || | ||
492 | state->crtc_h > INT_MAX || | ||
493 | state->crtc_y > INT_MAX - (int32_t) state->crtc_h) { | ||
494 | DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", | ||
495 | state->crtc_w, state->crtc_h, | ||
496 | state->crtc_x, state->crtc_y); | ||
497 | return -ERANGE; | ||
498 | } | ||
499 | |||
500 | fb_width = state->fb->width << 16; | ||
501 | fb_height = state->fb->height << 16; | ||
502 | |||
503 | /* Make sure source coordinates are inside the fb. */ | ||
504 | if (state->src_w > fb_width || | ||
505 | state->src_x > fb_width - state->src_w || | ||
506 | state->src_h > fb_height || | ||
507 | state->src_y > fb_height - state->src_h) { | ||
508 | DRM_DEBUG_KMS("Invalid source coordinates " | ||
509 | "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", | ||
510 | state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10, | ||
511 | state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10, | ||
512 | state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10, | ||
513 | state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10); | ||
514 | return -ENOSPC; | ||
515 | } | ||
516 | |||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | /** | ||
275 | * drm_atomic_get_connector_state - get connector state | 521 | * drm_atomic_get_connector_state - get connector state |
276 | * @state: global atomic state object | 522 | * @state: global atomic state object |
277 | * @connector: connector to get state object for | 523 | * @connector: connector to get state object for |
@@ -343,9 +589,113 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, | |||
343 | EXPORT_SYMBOL(drm_atomic_get_connector_state); | 589 | EXPORT_SYMBOL(drm_atomic_get_connector_state); |
344 | 590 | ||
345 | /** | 591 | /** |
592 | * drm_atomic_connector_set_property - set property on connector. | ||
593 | * @connector: the drm connector to set a property on | ||
594 | * @state: the state object to update with the new property value | ||
595 | * @property: the property to set | ||
596 | * @val: the new property value | ||
597 | * | ||
598 | * Use this instead of calling connector->atomic_set_property directly. | ||
599 | * This function handles generic/core properties and calls out to | ||
600 | * driver's ->atomic_set_property() for driver properties. To ensure | ||
601 | * consistent behavior you must call this function rather than the | ||
602 | * driver hook directly. | ||
603 | * | ||
604 | * RETURNS: | ||
605 | * Zero on success, error code on failure | ||
606 | */ | ||
607 | int drm_atomic_connector_set_property(struct drm_connector *connector, | ||
608 | struct drm_connector_state *state, struct drm_property *property, | ||
609 | uint64_t val) | ||
610 | { | ||
611 | struct drm_device *dev = connector->dev; | ||
612 | struct drm_mode_config *config = &dev->mode_config; | ||
613 | |||
614 | if (property == config->prop_crtc_id) { | ||
615 | struct drm_crtc *crtc = drm_crtc_find(dev, val); | ||
616 | return drm_atomic_set_crtc_for_connector(state, crtc); | ||
617 | } else if (property == config->dpms_property) { | ||
618 | /* setting DPMS property requires special handling, which | ||
619 | * is done in legacy setprop path for us. Disallow (for | ||
620 | * now?) atomic writes to DPMS property: | ||
621 | */ | ||
622 | return -EINVAL; | ||
623 | } else if (connector->funcs->atomic_set_property) { | ||
624 | return connector->funcs->atomic_set_property(connector, | ||
625 | state, property, val); | ||
626 | } else { | ||
627 | return -EINVAL; | ||
628 | } | ||
629 | } | ||
630 | EXPORT_SYMBOL(drm_atomic_connector_set_property); | ||
631 | |||
632 | /* | ||
633 | * This function handles generic/core properties and calls out to | ||
634 | * driver's ->atomic_get_property() for driver properties. To ensure | ||
635 | * consistent behavior you must call this function rather than the | ||
636 | * driver hook directly. | ||
637 | */ | ||
638 | static int | ||
639 | drm_atomic_connector_get_property(struct drm_connector *connector, | ||
640 | const struct drm_connector_state *state, | ||
641 | struct drm_property *property, uint64_t *val) | ||
642 | { | ||
643 | struct drm_device *dev = connector->dev; | ||
644 | struct drm_mode_config *config = &dev->mode_config; | ||
645 | |||
646 | if (property == config->prop_crtc_id) { | ||
647 | *val = (state->crtc) ? state->crtc->base.id : 0; | ||
648 | } else if (property == config->dpms_property) { | ||
649 | *val = connector->dpms; | ||
650 | } else if (connector->funcs->atomic_get_property) { | ||
651 | return connector->funcs->atomic_get_property(connector, | ||
652 | state, property, val); | ||
653 | } else { | ||
654 | return -EINVAL; | ||
655 | } | ||
656 | |||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | int drm_atomic_get_property(struct drm_mode_object *obj, | ||
661 | struct drm_property *property, uint64_t *val) | ||
662 | { | ||
663 | struct drm_device *dev = property->dev; | ||
664 | int ret; | ||
665 | |||
666 | switch (obj->type) { | ||
667 | case DRM_MODE_OBJECT_CONNECTOR: { | ||
668 | struct drm_connector *connector = obj_to_connector(obj); | ||
669 | WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); | ||
670 | ret = drm_atomic_connector_get_property(connector, | ||
671 | connector->state, property, val); | ||
672 | break; | ||
673 | } | ||
674 | case DRM_MODE_OBJECT_CRTC: { | ||
675 | struct drm_crtc *crtc = obj_to_crtc(obj); | ||
676 | WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); | ||
677 | ret = drm_atomic_crtc_get_property(crtc, | ||
678 | crtc->state, property, val); | ||
679 | break; | ||
680 | } | ||
681 | case DRM_MODE_OBJECT_PLANE: { | ||
682 | struct drm_plane *plane = obj_to_plane(obj); | ||
683 | WARN_ON(!drm_modeset_is_locked(&plane->mutex)); | ||
684 | ret = drm_atomic_plane_get_property(plane, | ||
685 | plane->state, property, val); | ||
686 | break; | ||
687 | } | ||
688 | default: | ||
689 | ret = -EINVAL; | ||
690 | break; | ||
691 | } | ||
692 | |||
693 | return ret; | ||
694 | } | ||
695 | |||
696 | /** | ||
346 | * drm_atomic_set_crtc_for_plane - set crtc for plane | 697 | * drm_atomic_set_crtc_for_plane - set crtc for plane |
347 | * @state: the incoming atomic state | 698 | * @plane_state: the plane whose incoming state to update |
348 | * @plane: the plane whose incoming state to update | ||
349 | * @crtc: crtc to use for the plane | 699 | * @crtc: crtc to use for the plane |
350 | * | 700 | * |
351 | * Changing the assigned crtc for a plane requires us to grab the lock and state | 701 | * Changing the assigned crtc for a plane requires us to grab the lock and state |
@@ -358,16 +708,12 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state); | |||
358 | * sequence must be restarted. All other errors are fatal. | 708 | * sequence must be restarted. All other errors are fatal. |
359 | */ | 709 | */ |
360 | int | 710 | int |
361 | drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state, | 711 | drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, |
362 | struct drm_plane *plane, struct drm_crtc *crtc) | 712 | struct drm_crtc *crtc) |
363 | { | 713 | { |
364 | struct drm_plane_state *plane_state = | 714 | struct drm_plane *plane = plane_state->plane; |
365 | drm_atomic_get_plane_state(state, plane); | ||
366 | struct drm_crtc_state *crtc_state; | 715 | struct drm_crtc_state *crtc_state; |
367 | 716 | ||
368 | if (WARN_ON(IS_ERR(plane_state))) | ||
369 | return PTR_ERR(plane_state); | ||
370 | |||
371 | if (plane_state->crtc) { | 717 | if (plane_state->crtc) { |
372 | crtc_state = drm_atomic_get_crtc_state(plane_state->state, | 718 | crtc_state = drm_atomic_get_crtc_state(plane_state->state, |
373 | plane_state->crtc); | 719 | plane_state->crtc); |
@@ -583,14 +929,62 @@ EXPORT_SYMBOL(drm_atomic_legacy_backoff); | |||
583 | */ | 929 | */ |
584 | int drm_atomic_check_only(struct drm_atomic_state *state) | 930 | int drm_atomic_check_only(struct drm_atomic_state *state) |
585 | { | 931 | { |
586 | struct drm_mode_config *config = &state->dev->mode_config; | 932 | struct drm_device *dev = state->dev; |
933 | struct drm_mode_config *config = &dev->mode_config; | ||
934 | int nplanes = config->num_total_plane; | ||
935 | int ncrtcs = config->num_crtc; | ||
936 | int i, ret = 0; | ||
587 | 937 | ||
588 | DRM_DEBUG_KMS("checking %p\n", state); | 938 | DRM_DEBUG_KMS("checking %p\n", state); |
589 | 939 | ||
940 | for (i = 0; i < nplanes; i++) { | ||
941 | struct drm_plane *plane = state->planes[i]; | ||
942 | |||
943 | if (!plane) | ||
944 | continue; | ||
945 | |||
946 | ret = drm_atomic_plane_check(plane, state->plane_states[i]); | ||
947 | if (ret) { | ||
948 | DRM_DEBUG_KMS("[PLANE:%d] atomic core check failed\n", | ||
949 | plane->base.id); | ||
950 | return ret; | ||
951 | } | ||
952 | } | ||
953 | |||
954 | for (i = 0; i < ncrtcs; i++) { | ||
955 | struct drm_crtc *crtc = state->crtcs[i]; | ||
956 | |||
957 | if (!crtc) | ||
958 | continue; | ||
959 | |||
960 | ret = drm_atomic_crtc_check(crtc, state->crtc_states[i]); | ||
961 | if (ret) { | ||
962 | DRM_DEBUG_KMS("[CRTC:%d] atomic core check failed\n", | ||
963 | crtc->base.id); | ||
964 | return ret; | ||
965 | } | ||
966 | } | ||
967 | |||
590 | if (config->funcs->atomic_check) | 968 | if (config->funcs->atomic_check) |
591 | return config->funcs->atomic_check(state->dev, state); | 969 | ret = config->funcs->atomic_check(state->dev, state); |
592 | else | 970 | |
593 | return 0; | 971 | if (!state->allow_modeset) { |
972 | for (i = 0; i < ncrtcs; i++) { | ||
973 | struct drm_crtc *crtc = state->crtcs[i]; | ||
974 | struct drm_crtc_state *crtc_state = state->crtc_states[i]; | ||
975 | |||
976 | if (!crtc) | ||
977 | continue; | ||
978 | |||
979 | if (crtc_state->mode_changed) { | ||
980 | DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n", | ||
981 | crtc->base.id); | ||
982 | return -EINVAL; | ||
983 | } | ||
984 | } | ||
985 | } | ||
986 | |||
987 | return ret; | ||
594 | } | 988 | } |
595 | EXPORT_SYMBOL(drm_atomic_check_only); | 989 | EXPORT_SYMBOL(drm_atomic_check_only); |
596 | 990 | ||
@@ -655,3 +1049,313 @@ int drm_atomic_async_commit(struct drm_atomic_state *state) | |||
655 | return config->funcs->atomic_commit(state->dev, state, true); | 1049 | return config->funcs->atomic_commit(state->dev, state, true); |
656 | } | 1050 | } |
657 | EXPORT_SYMBOL(drm_atomic_async_commit); | 1051 | EXPORT_SYMBOL(drm_atomic_async_commit); |
1052 | |||
1053 | /* | ||
1054 | * The big monstor ioctl | ||
1055 | */ | ||
1056 | |||
1057 | static struct drm_pending_vblank_event *create_vblank_event( | ||
1058 | struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data) | ||
1059 | { | ||
1060 | struct drm_pending_vblank_event *e = NULL; | ||
1061 | unsigned long flags; | ||
1062 | |||
1063 | spin_lock_irqsave(&dev->event_lock, flags); | ||
1064 | if (file_priv->event_space < sizeof e->event) { | ||
1065 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
1066 | goto out; | ||
1067 | } | ||
1068 | file_priv->event_space -= sizeof e->event; | ||
1069 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
1070 | |||
1071 | e = kzalloc(sizeof *e, GFP_KERNEL); | ||
1072 | if (e == NULL) { | ||
1073 | spin_lock_irqsave(&dev->event_lock, flags); | ||
1074 | file_priv->event_space += sizeof e->event; | ||
1075 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
1076 | goto out; | ||
1077 | } | ||
1078 | |||
1079 | e->event.base.type = DRM_EVENT_FLIP_COMPLETE; | ||
1080 | e->event.base.length = sizeof e->event; | ||
1081 | e->event.user_data = user_data; | ||
1082 | e->base.event = &e->event.base; | ||
1083 | e->base.file_priv = file_priv; | ||
1084 | e->base.destroy = (void (*) (struct drm_pending_event *)) kfree; | ||
1085 | |||
1086 | out: | ||
1087 | return e; | ||
1088 | } | ||
1089 | |||
1090 | static void destroy_vblank_event(struct drm_device *dev, | ||
1091 | struct drm_file *file_priv, struct drm_pending_vblank_event *e) | ||
1092 | { | ||
1093 | unsigned long flags; | ||
1094 | |||
1095 | spin_lock_irqsave(&dev->event_lock, flags); | ||
1096 | file_priv->event_space += sizeof e->event; | ||
1097 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
1098 | kfree(e); | ||
1099 | } | ||
1100 | |||
1101 | static int atomic_set_prop(struct drm_atomic_state *state, | ||
1102 | struct drm_mode_object *obj, struct drm_property *prop, | ||
1103 | uint64_t prop_value) | ||
1104 | { | ||
1105 | struct drm_mode_object *ref; | ||
1106 | int ret; | ||
1107 | |||
1108 | if (!drm_property_change_valid_get(prop, prop_value, &ref)) | ||
1109 | return -EINVAL; | ||
1110 | |||
1111 | switch (obj->type) { | ||
1112 | case DRM_MODE_OBJECT_CONNECTOR: { | ||
1113 | struct drm_connector *connector = obj_to_connector(obj); | ||
1114 | struct drm_connector_state *connector_state; | ||
1115 | |||
1116 | connector_state = drm_atomic_get_connector_state(state, connector); | ||
1117 | if (IS_ERR(connector_state)) { | ||
1118 | ret = PTR_ERR(connector_state); | ||
1119 | break; | ||
1120 | } | ||
1121 | |||
1122 | ret = drm_atomic_connector_set_property(connector, | ||
1123 | connector_state, prop, prop_value); | ||
1124 | break; | ||
1125 | } | ||
1126 | case DRM_MODE_OBJECT_CRTC: { | ||
1127 | struct drm_crtc *crtc = obj_to_crtc(obj); | ||
1128 | struct drm_crtc_state *crtc_state; | ||
1129 | |||
1130 | crtc_state = drm_atomic_get_crtc_state(state, crtc); | ||
1131 | if (IS_ERR(crtc_state)) { | ||
1132 | ret = PTR_ERR(crtc_state); | ||
1133 | break; | ||
1134 | } | ||
1135 | |||
1136 | ret = drm_atomic_crtc_set_property(crtc, | ||
1137 | crtc_state, prop, prop_value); | ||
1138 | break; | ||
1139 | } | ||
1140 | case DRM_MODE_OBJECT_PLANE: { | ||
1141 | struct drm_plane *plane = obj_to_plane(obj); | ||
1142 | struct drm_plane_state *plane_state; | ||
1143 | |||
1144 | plane_state = drm_atomic_get_plane_state(state, plane); | ||
1145 | if (IS_ERR(plane_state)) { | ||
1146 | ret = PTR_ERR(plane_state); | ||
1147 | break; | ||
1148 | } | ||
1149 | |||
1150 | ret = drm_atomic_plane_set_property(plane, | ||
1151 | plane_state, prop, prop_value); | ||
1152 | break; | ||
1153 | } | ||
1154 | default: | ||
1155 | ret = -EINVAL; | ||
1156 | break; | ||
1157 | } | ||
1158 | |||
1159 | drm_property_change_valid_put(prop, ref); | ||
1160 | return ret; | ||
1161 | } | ||
1162 | |||
1163 | int drm_mode_atomic_ioctl(struct drm_device *dev, | ||
1164 | void *data, struct drm_file *file_priv) | ||
1165 | { | ||
1166 | struct drm_mode_atomic *arg = data; | ||
1167 | uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr); | ||
1168 | uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr); | ||
1169 | uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr); | ||
1170 | uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr); | ||
1171 | unsigned int copied_objs, copied_props; | ||
1172 | struct drm_atomic_state *state; | ||
1173 | struct drm_modeset_acquire_ctx ctx; | ||
1174 | struct drm_plane *plane; | ||
1175 | unsigned plane_mask = 0; | ||
1176 | int ret = 0; | ||
1177 | unsigned int i, j; | ||
1178 | |||
1179 | /* disallow for drivers not supporting atomic: */ | ||
1180 | if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) | ||
1181 | return -EINVAL; | ||
1182 | |||
1183 | /* disallow for userspace that has not enabled atomic cap (even | ||
1184 | * though this may be a bit overkill, since legacy userspace | ||
1185 | * wouldn't know how to call this ioctl) | ||
1186 | */ | ||
1187 | if (!file_priv->atomic) | ||
1188 | return -EINVAL; | ||
1189 | |||
1190 | if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS) | ||
1191 | return -EINVAL; | ||
1192 | |||
1193 | if (arg->reserved) | ||
1194 | return -EINVAL; | ||
1195 | |||
1196 | if ((arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) && | ||
1197 | !dev->mode_config.async_page_flip) | ||
1198 | return -EINVAL; | ||
1199 | |||
1200 | /* can't test and expect an event at the same time. */ | ||
1201 | if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) && | ||
1202 | (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) | ||
1203 | return -EINVAL; | ||
1204 | |||
1205 | drm_modeset_acquire_init(&ctx, 0); | ||
1206 | |||
1207 | state = drm_atomic_state_alloc(dev); | ||
1208 | if (!state) | ||
1209 | return -ENOMEM; | ||
1210 | |||
1211 | state->acquire_ctx = &ctx; | ||
1212 | state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET); | ||
1213 | |||
1214 | retry: | ||
1215 | copied_objs = 0; | ||
1216 | copied_props = 0; | ||
1217 | |||
1218 | for (i = 0; i < arg->count_objs; i++) { | ||
1219 | uint32_t obj_id, count_props; | ||
1220 | struct drm_mode_object *obj; | ||
1221 | |||
1222 | if (get_user(obj_id, objs_ptr + copied_objs)) { | ||
1223 | ret = -EFAULT; | ||
1224 | goto fail; | ||
1225 | } | ||
1226 | |||
1227 | obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY); | ||
1228 | if (!obj || !obj->properties) { | ||
1229 | ret = -ENOENT; | ||
1230 | goto fail; | ||
1231 | } | ||
1232 | |||
1233 | if (obj->type == DRM_MODE_OBJECT_PLANE) { | ||
1234 | plane = obj_to_plane(obj); | ||
1235 | plane_mask |= (1 << drm_plane_index(plane)); | ||
1236 | plane->old_fb = plane->fb; | ||
1237 | } | ||
1238 | |||
1239 | if (get_user(count_props, count_props_ptr + copied_objs)) { | ||
1240 | ret = -EFAULT; | ||
1241 | goto fail; | ||
1242 | } | ||
1243 | |||
1244 | copied_objs++; | ||
1245 | |||
1246 | for (j = 0; j < count_props; j++) { | ||
1247 | uint32_t prop_id; | ||
1248 | uint64_t prop_value; | ||
1249 | struct drm_property *prop; | ||
1250 | |||
1251 | if (get_user(prop_id, props_ptr + copied_props)) { | ||
1252 | ret = -EFAULT; | ||
1253 | goto fail; | ||
1254 | } | ||
1255 | |||
1256 | prop = drm_property_find(dev, prop_id); | ||
1257 | if (!prop) { | ||
1258 | ret = -ENOENT; | ||
1259 | goto fail; | ||
1260 | } | ||
1261 | |||
1262 | if (get_user(prop_value, prop_values_ptr + copied_props)) { | ||
1263 | ret = -EFAULT; | ||
1264 | goto fail; | ||
1265 | } | ||
1266 | |||
1267 | ret = atomic_set_prop(state, obj, prop, prop_value); | ||
1268 | if (ret) | ||
1269 | goto fail; | ||
1270 | |||
1271 | copied_props++; | ||
1272 | } | ||
1273 | } | ||
1274 | |||
1275 | if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { | ||
1276 | int ncrtcs = dev->mode_config.num_crtc; | ||
1277 | |||
1278 | for (i = 0; i < ncrtcs; i++) { | ||
1279 | struct drm_crtc_state *crtc_state = state->crtc_states[i]; | ||
1280 | struct drm_pending_vblank_event *e; | ||
1281 | |||
1282 | if (!crtc_state) | ||
1283 | continue; | ||
1284 | |||
1285 | e = create_vblank_event(dev, file_priv, arg->user_data); | ||
1286 | if (!e) { | ||
1287 | ret = -ENOMEM; | ||
1288 | goto fail; | ||
1289 | } | ||
1290 | |||
1291 | crtc_state->event = e; | ||
1292 | } | ||
1293 | } | ||
1294 | |||
1295 | if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { | ||
1296 | ret = drm_atomic_check_only(state); | ||
1297 | /* _check_only() does not free state, unlike _commit() */ | ||
1298 | drm_atomic_state_free(state); | ||
1299 | } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) { | ||
1300 | ret = drm_atomic_async_commit(state); | ||
1301 | } else { | ||
1302 | ret = drm_atomic_commit(state); | ||
1303 | } | ||
1304 | |||
1305 | /* if succeeded, fixup legacy plane crtc/fb ptrs before dropping | ||
1306 | * locks (ie. while it is still safe to deref plane->state). We | ||
1307 | * need to do this here because the driver entry points cannot | ||
1308 | * distinguish between legacy and atomic ioctls. | ||
1309 | */ | ||
1310 | drm_for_each_plane_mask(plane, dev, plane_mask) { | ||
1311 | if (ret == 0) { | ||
1312 | struct drm_framebuffer *new_fb = plane->state->fb; | ||
1313 | if (new_fb) | ||
1314 | drm_framebuffer_reference(new_fb); | ||
1315 | plane->fb = new_fb; | ||
1316 | plane->crtc = plane->state->crtc; | ||
1317 | } else { | ||
1318 | plane->old_fb = NULL; | ||
1319 | } | ||
1320 | if (plane->old_fb) { | ||
1321 | drm_framebuffer_unreference(plane->old_fb); | ||
1322 | plane->old_fb = NULL; | ||
1323 | } | ||
1324 | } | ||
1325 | |||
1326 | drm_modeset_drop_locks(&ctx); | ||
1327 | drm_modeset_acquire_fini(&ctx); | ||
1328 | |||
1329 | return ret; | ||
1330 | |||
1331 | fail: | ||
1332 | if (ret == -EDEADLK) | ||
1333 | goto backoff; | ||
1334 | |||
1335 | if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { | ||
1336 | int ncrtcs = dev->mode_config.num_crtc; | ||
1337 | |||
1338 | for (i = 0; i < ncrtcs; i++) { | ||
1339 | struct drm_crtc_state *crtc_state = state->crtc_states[i]; | ||
1340 | |||
1341 | if (!crtc_state) | ||
1342 | continue; | ||
1343 | |||
1344 | destroy_vblank_event(dev, file_priv, crtc_state->event); | ||
1345 | crtc_state->event = NULL; | ||
1346 | } | ||
1347 | } | ||
1348 | |||
1349 | drm_atomic_state_free(state); | ||
1350 | |||
1351 | drm_modeset_drop_locks(&ctx); | ||
1352 | drm_modeset_acquire_fini(&ctx); | ||
1353 | |||
1354 | return ret; | ||
1355 | |||
1356 | backoff: | ||
1357 | drm_atomic_state_clear(state); | ||
1358 | drm_modeset_backoff(&ctx); | ||
1359 | |||
1360 | goto retry; | ||
1361 | } | ||
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index bbdbe4721573..541ba833ed36 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
@@ -330,7 +330,29 @@ mode_fixup(struct drm_atomic_state *state) | |||
330 | return 0; | 330 | return 0; |
331 | } | 331 | } |
332 | 332 | ||
333 | static int | 333 | /** |
334 | * drm_atomic_helper_check - validate state object for modeset changes | ||
335 | * @dev: DRM device | ||
336 | * @state: the driver state object | ||
337 | * | ||
338 | * Check the state object to see if the requested state is physically possible. | ||
339 | * This does all the crtc and connector related computations for an atomic | ||
340 | * update. It computes and updates crtc_state->mode_changed, adds any additional | ||
341 | * connectors needed for full modesets and calls down into ->mode_fixup | ||
342 | * functions of the driver backend. | ||
343 | * | ||
344 | * IMPORTANT: | ||
345 | * | ||
346 | * Drivers which update ->mode_changed (e.g. in their ->atomic_check hooks if a | ||
347 | * plane update can't be done without a full modeset) _must_ call this function | ||
348 | * afterwards after that change. It is permitted to call this function multiple | ||
349 | * times for the same update, e.g. when the ->atomic_check functions depend upon | ||
350 | * the adjusted dotclock for fifo space allocation and watermark computation. | ||
351 | * | ||
352 | * RETURNS | ||
353 | * Zero for success or -errno | ||
354 | */ | ||
355 | int | ||
334 | drm_atomic_helper_check_modeset(struct drm_device *dev, | 356 | drm_atomic_helper_check_modeset(struct drm_device *dev, |
335 | struct drm_atomic_state *state) | 357 | struct drm_atomic_state *state) |
336 | { | 358 | { |
@@ -406,23 +428,23 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, | |||
406 | 428 | ||
407 | return mode_fixup(state); | 429 | return mode_fixup(state); |
408 | } | 430 | } |
431 | EXPORT_SYMBOL(drm_atomic_helper_check_modeset); | ||
409 | 432 | ||
410 | /** | 433 | /** |
411 | * drm_atomic_helper_check - validate state object | 434 | * drm_atomic_helper_check - validate state object for modeset changes |
412 | * @dev: DRM device | 435 | * @dev: DRM device |
413 | * @state: the driver state object | 436 | * @state: the driver state object |
414 | * | 437 | * |
415 | * Check the state object to see if the requested state is physically possible. | 438 | * Check the state object to see if the requested state is physically possible. |
416 | * Only crtcs and planes have check callbacks, so for any additional (global) | 439 | * This does all the plane update related checks using by calling into the |
417 | * checking that a driver needs it can simply wrap that around this function. | 440 | * ->atomic_check hooks provided by the driver. |
418 | * Drivers without such needs can directly use this as their ->atomic_check() | ||
419 | * callback. | ||
420 | * | 441 | * |
421 | * RETURNS | 442 | * RETURNS |
422 | * Zero for success or -errno | 443 | * Zero for success or -errno |
423 | */ | 444 | */ |
424 | int drm_atomic_helper_check(struct drm_device *dev, | 445 | int |
425 | struct drm_atomic_state *state) | 446 | drm_atomic_helper_check_planes(struct drm_device *dev, |
447 | struct drm_atomic_state *state) | ||
426 | { | 448 | { |
427 | int nplanes = dev->mode_config.num_total_plane; | 449 | int nplanes = dev->mode_config.num_total_plane; |
428 | int ncrtcs = dev->mode_config.num_crtc; | 450 | int ncrtcs = dev->mode_config.num_crtc; |
@@ -445,7 +467,7 @@ int drm_atomic_helper_check(struct drm_device *dev, | |||
445 | 467 | ||
446 | ret = funcs->atomic_check(plane, plane_state); | 468 | ret = funcs->atomic_check(plane, plane_state); |
447 | if (ret) { | 469 | if (ret) { |
448 | DRM_DEBUG_KMS("[PLANE:%d] atomic check failed\n", | 470 | DRM_DEBUG_KMS("[PLANE:%d] atomic driver check failed\n", |
449 | plane->base.id); | 471 | plane->base.id); |
450 | return ret; | 472 | return ret; |
451 | } | 473 | } |
@@ -465,16 +487,49 @@ int drm_atomic_helper_check(struct drm_device *dev, | |||
465 | 487 | ||
466 | ret = funcs->atomic_check(crtc, state->crtc_states[i]); | 488 | ret = funcs->atomic_check(crtc, state->crtc_states[i]); |
467 | if (ret) { | 489 | if (ret) { |
468 | DRM_DEBUG_KMS("[CRTC:%d] atomic check failed\n", | 490 | DRM_DEBUG_KMS("[CRTC:%d] atomic driver check failed\n", |
469 | crtc->base.id); | 491 | crtc->base.id); |
470 | return ret; | 492 | return ret; |
471 | } | 493 | } |
472 | } | 494 | } |
473 | 495 | ||
496 | return ret; | ||
497 | } | ||
498 | EXPORT_SYMBOL(drm_atomic_helper_check_planes); | ||
499 | |||
500 | /** | ||
501 | * drm_atomic_helper_check - validate state object | ||
502 | * @dev: DRM device | ||
503 | * @state: the driver state object | ||
504 | * | ||
505 | * Check the state object to see if the requested state is physically possible. | ||
506 | * Only crtcs and planes have check callbacks, so for any additional (global) | ||
507 | * checking that a driver needs it can simply wrap that around this function. | ||
508 | * Drivers without such needs can directly use this as their ->atomic_check() | ||
509 | * callback. | ||
510 | * | ||
511 | * This just wraps the two parts of the state checking for planes and modeset | ||
512 | * state in the default order: First it calls drm_atomic_helper_check_modeset() | ||
513 | * and then drm_atomic_helper_check_planes(). The assumption is that the | ||
514 | * ->atomic_check functions depend upon an updated adjusted_mode.clock to | ||
515 | * e.g. properly compute watermarks. | ||
516 | * | ||
517 | * RETURNS | ||
518 | * Zero for success or -errno | ||
519 | */ | ||
520 | int drm_atomic_helper_check(struct drm_device *dev, | ||
521 | struct drm_atomic_state *state) | ||
522 | { | ||
523 | int ret; | ||
524 | |||
474 | ret = drm_atomic_helper_check_modeset(dev, state); | 525 | ret = drm_atomic_helper_check_modeset(dev, state); |
475 | if (ret) | 526 | if (ret) |
476 | return ret; | 527 | return ret; |
477 | 528 | ||
529 | ret = drm_atomic_helper_check_planes(dev, state); | ||
530 | if (ret) | ||
531 | return ret; | ||
532 | |||
478 | return ret; | 533 | return ret; |
479 | } | 534 | } |
480 | EXPORT_SYMBOL(drm_atomic_helper_check); | 535 | EXPORT_SYMBOL(drm_atomic_helper_check); |
@@ -1222,7 +1277,7 @@ retry: | |||
1222 | goto fail; | 1277 | goto fail; |
1223 | } | 1278 | } |
1224 | 1279 | ||
1225 | ret = drm_atomic_set_crtc_for_plane(state, plane, crtc); | 1280 | ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); |
1226 | if (ret != 0) | 1281 | if (ret != 0) |
1227 | goto fail; | 1282 | goto fail; |
1228 | drm_atomic_set_fb_for_plane(plane_state, fb); | 1283 | drm_atomic_set_fb_for_plane(plane_state, fb); |
@@ -1301,7 +1356,7 @@ retry: | |||
1301 | goto fail; | 1356 | goto fail; |
1302 | } | 1357 | } |
1303 | 1358 | ||
1304 | ret = drm_atomic_set_crtc_for_plane(state, plane, NULL); | 1359 | ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); |
1305 | if (ret != 0) | 1360 | if (ret != 0) |
1306 | goto fail; | 1361 | goto fail; |
1307 | drm_atomic_set_fb_for_plane(plane_state, NULL); | 1362 | drm_atomic_set_fb_for_plane(plane_state, NULL); |
@@ -1464,7 +1519,7 @@ retry: | |||
1464 | 1519 | ||
1465 | crtc_state->enable = false; | 1520 | crtc_state->enable = false; |
1466 | 1521 | ||
1467 | ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, NULL); | 1522 | ret = drm_atomic_set_crtc_for_plane(primary_state, NULL); |
1468 | if (ret != 0) | 1523 | if (ret != 0) |
1469 | goto fail; | 1524 | goto fail; |
1470 | 1525 | ||
@@ -1479,7 +1534,7 @@ retry: | |||
1479 | crtc_state->enable = true; | 1534 | crtc_state->enable = true; |
1480 | drm_mode_copy(&crtc_state->mode, set->mode); | 1535 | drm_mode_copy(&crtc_state->mode, set->mode); |
1481 | 1536 | ||
1482 | ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, crtc); | 1537 | ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); |
1483 | if (ret != 0) | 1538 | if (ret != 0) |
1484 | goto fail; | 1539 | goto fail; |
1485 | drm_atomic_set_fb_for_plane(primary_state, set->fb); | 1540 | drm_atomic_set_fb_for_plane(primary_state, set->fb); |
@@ -1558,8 +1613,8 @@ retry: | |||
1558 | goto fail; | 1613 | goto fail; |
1559 | } | 1614 | } |
1560 | 1615 | ||
1561 | ret = crtc->funcs->atomic_set_property(crtc, crtc_state, | 1616 | ret = drm_atomic_crtc_set_property(crtc, crtc_state, |
1562 | property, val); | 1617 | property, val); |
1563 | if (ret) | 1618 | if (ret) |
1564 | goto fail; | 1619 | goto fail; |
1565 | 1620 | ||
@@ -1617,8 +1672,8 @@ retry: | |||
1617 | goto fail; | 1672 | goto fail; |
1618 | } | 1673 | } |
1619 | 1674 | ||
1620 | ret = plane->funcs->atomic_set_property(plane, plane_state, | 1675 | ret = drm_atomic_plane_set_property(plane, plane_state, |
1621 | property, val); | 1676 | property, val); |
1622 | if (ret) | 1677 | if (ret) |
1623 | goto fail; | 1678 | goto fail; |
1624 | 1679 | ||
@@ -1676,8 +1731,8 @@ retry: | |||
1676 | goto fail; | 1731 | goto fail; |
1677 | } | 1732 | } |
1678 | 1733 | ||
1679 | ret = connector->funcs->atomic_set_property(connector, connector_state, | 1734 | ret = drm_atomic_connector_set_property(connector, connector_state, |
1680 | property, val); | 1735 | property, val); |
1681 | if (ret) | 1736 | if (ret) |
1682 | goto fail; | 1737 | goto fail; |
1683 | 1738 | ||
@@ -1751,7 +1806,7 @@ retry: | |||
1751 | goto fail; | 1806 | goto fail; |
1752 | } | 1807 | } |
1753 | 1808 | ||
1754 | ret = drm_atomic_set_crtc_for_plane(state, plane, crtc); | 1809 | ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); |
1755 | if (ret != 0) | 1810 | if (ret != 0) |
1756 | goto fail; | 1811 | goto fail; |
1757 | drm_atomic_set_fb_for_plane(plane_state, fb); | 1812 | drm_atomic_set_fb_for_plane(plane_state, fb); |
@@ -1814,6 +1869,9 @@ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc) | |||
1814 | { | 1869 | { |
1815 | kfree(crtc->state); | 1870 | kfree(crtc->state); |
1816 | crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL); | 1871 | crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL); |
1872 | |||
1873 | if (crtc->state) | ||
1874 | crtc->state->crtc = crtc; | ||
1817 | } | 1875 | } |
1818 | EXPORT_SYMBOL(drm_atomic_helper_crtc_reset); | 1876 | EXPORT_SYMBOL(drm_atomic_helper_crtc_reset); |
1819 | 1877 | ||
@@ -1873,6 +1931,9 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane) | |||
1873 | 1931 | ||
1874 | kfree(plane->state); | 1932 | kfree(plane->state); |
1875 | plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL); | 1933 | plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL); |
1934 | |||
1935 | if (plane->state) | ||
1936 | plane->state->plane = plane; | ||
1876 | } | 1937 | } |
1877 | EXPORT_SYMBOL(drm_atomic_helper_plane_reset); | 1938 | EXPORT_SYMBOL(drm_atomic_helper_plane_reset); |
1878 | 1939 | ||
@@ -1930,6 +1991,9 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector) | |||
1930 | { | 1991 | { |
1931 | kfree(connector->state); | 1992 | kfree(connector->state); |
1932 | connector->state = kzalloc(sizeof(*connector->state), GFP_KERNEL); | 1993 | connector->state = kzalloc(sizeof(*connector->state), GFP_KERNEL); |
1994 | |||
1995 | if (connector->state) | ||
1996 | connector->state->connector = connector; | ||
1933 | } | 1997 | } |
1934 | EXPORT_SYMBOL(drm_atomic_helper_connector_reset); | 1998 | EXPORT_SYMBOL(drm_atomic_helper_connector_reset); |
1935 | 1999 | ||
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 2892d746a1e9..7e4acad3f6f9 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <drm/drm_edid.h> | 38 | #include <drm/drm_edid.h> |
39 | #include <drm/drm_fourcc.h> | 39 | #include <drm/drm_fourcc.h> |
40 | #include <drm/drm_modeset_lock.h> | 40 | #include <drm/drm_modeset_lock.h> |
41 | #include <drm/drm_atomic.h> | ||
41 | 42 | ||
42 | #include "drm_crtc_internal.h" | 43 | #include "drm_crtc_internal.h" |
43 | #include "drm_internal.h" | 44 | #include "drm_internal.h" |
@@ -830,6 +831,7 @@ int drm_connector_init(struct drm_device *dev, | |||
830 | const struct drm_connector_funcs *funcs, | 831 | const struct drm_connector_funcs *funcs, |
831 | int connector_type) | 832 | int connector_type) |
832 | { | 833 | { |
834 | struct drm_mode_config *config = &dev->mode_config; | ||
833 | int ret; | 835 | int ret; |
834 | struct ida *connector_ida = | 836 | struct ida *connector_ida = |
835 | &drm_connector_enum_list[connector_type].ida; | 837 | &drm_connector_enum_list[connector_type].ida; |
@@ -868,16 +870,20 @@ int drm_connector_init(struct drm_device *dev, | |||
868 | 870 | ||
869 | /* We should add connectors at the end to avoid upsetting the connector | 871 | /* We should add connectors at the end to avoid upsetting the connector |
870 | * index too much. */ | 872 | * index too much. */ |
871 | list_add_tail(&connector->head, &dev->mode_config.connector_list); | 873 | list_add_tail(&connector->head, &config->connector_list); |
872 | dev->mode_config.num_connector++; | 874 | config->num_connector++; |
873 | 875 | ||
874 | if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) | 876 | if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) |
875 | drm_object_attach_property(&connector->base, | 877 | drm_object_attach_property(&connector->base, |
876 | dev->mode_config.edid_property, | 878 | config->edid_property, |
877 | 0); | 879 | 0); |
878 | 880 | ||
879 | drm_object_attach_property(&connector->base, | 881 | drm_object_attach_property(&connector->base, |
880 | dev->mode_config.dpms_property, 0); | 882 | config->dpms_property, 0); |
883 | |||
884 | if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { | ||
885 | drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); | ||
886 | } | ||
881 | 887 | ||
882 | connector->debugfs_entry = NULL; | 888 | connector->debugfs_entry = NULL; |
883 | 889 | ||
@@ -1168,6 +1174,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
1168 | const uint32_t *formats, uint32_t format_count, | 1174 | const uint32_t *formats, uint32_t format_count, |
1169 | enum drm_plane_type type) | 1175 | enum drm_plane_type type) |
1170 | { | 1176 | { |
1177 | struct drm_mode_config *config = &dev->mode_config; | ||
1171 | int ret; | 1178 | int ret; |
1172 | 1179 | ||
1173 | ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); | 1180 | ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); |
@@ -1192,15 +1199,28 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
1192 | plane->possible_crtcs = possible_crtcs; | 1199 | plane->possible_crtcs = possible_crtcs; |
1193 | plane->type = type; | 1200 | plane->type = type; |
1194 | 1201 | ||
1195 | list_add_tail(&plane->head, &dev->mode_config.plane_list); | 1202 | list_add_tail(&plane->head, &config->plane_list); |
1196 | dev->mode_config.num_total_plane++; | 1203 | config->num_total_plane++; |
1197 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) | 1204 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) |
1198 | dev->mode_config.num_overlay_plane++; | 1205 | config->num_overlay_plane++; |
1199 | 1206 | ||
1200 | drm_object_attach_property(&plane->base, | 1207 | drm_object_attach_property(&plane->base, |
1201 | dev->mode_config.plane_type_property, | 1208 | config->plane_type_property, |
1202 | plane->type); | 1209 | plane->type); |
1203 | 1210 | ||
1211 | if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { | ||
1212 | drm_object_attach_property(&plane->base, config->prop_fb_id, 0); | ||
1213 | drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); | ||
1214 | drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); | ||
1215 | drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); | ||
1216 | drm_object_attach_property(&plane->base, config->prop_crtc_w, 0); | ||
1217 | drm_object_attach_property(&plane->base, config->prop_crtc_h, 0); | ||
1218 | drm_object_attach_property(&plane->base, config->prop_src_x, 0); | ||
1219 | drm_object_attach_property(&plane->base, config->prop_src_y, 0); | ||
1220 | drm_object_attach_property(&plane->base, config->prop_src_w, 0); | ||
1221 | drm_object_attach_property(&plane->base, config->prop_src_h, 0); | ||
1222 | } | ||
1223 | |||
1204 | return 0; | 1224 | return 0; |
1205 | } | 1225 | } |
1206 | EXPORT_SYMBOL(drm_universal_plane_init); | 1226 | EXPORT_SYMBOL(drm_universal_plane_init); |
@@ -1322,50 +1342,109 @@ void drm_plane_force_disable(struct drm_plane *plane) | |||
1322 | } | 1342 | } |
1323 | EXPORT_SYMBOL(drm_plane_force_disable); | 1343 | EXPORT_SYMBOL(drm_plane_force_disable); |
1324 | 1344 | ||
1325 | static int drm_mode_create_standard_connector_properties(struct drm_device *dev) | 1345 | static int drm_mode_create_standard_properties(struct drm_device *dev) |
1326 | { | 1346 | { |
1327 | struct drm_property *edid; | 1347 | struct drm_property *prop; |
1328 | struct drm_property *dpms; | ||
1329 | struct drm_property *dev_path; | ||
1330 | 1348 | ||
1331 | /* | 1349 | /* |
1332 | * Standard properties (apply to all connectors) | 1350 | * Standard properties (apply to all connectors) |
1333 | */ | 1351 | */ |
1334 | edid = drm_property_create(dev, DRM_MODE_PROP_BLOB | | 1352 | prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | |
1335 | DRM_MODE_PROP_IMMUTABLE, | 1353 | DRM_MODE_PROP_IMMUTABLE, |
1336 | "EDID", 0); | 1354 | "EDID", 0); |
1337 | dev->mode_config.edid_property = edid; | 1355 | if (!prop) |
1356 | return -ENOMEM; | ||
1357 | dev->mode_config.edid_property = prop; | ||
1338 | 1358 | ||
1339 | dpms = drm_property_create_enum(dev, 0, | 1359 | prop = drm_property_create_enum(dev, 0, |
1340 | "DPMS", drm_dpms_enum_list, | 1360 | "DPMS", drm_dpms_enum_list, |
1341 | ARRAY_SIZE(drm_dpms_enum_list)); | 1361 | ARRAY_SIZE(drm_dpms_enum_list)); |
1342 | dev->mode_config.dpms_property = dpms; | 1362 | if (!prop) |
1343 | 1363 | return -ENOMEM; | |
1344 | dev_path = drm_property_create(dev, | 1364 | dev->mode_config.dpms_property = prop; |
1345 | DRM_MODE_PROP_BLOB | | ||
1346 | DRM_MODE_PROP_IMMUTABLE, | ||
1347 | "PATH", 0); | ||
1348 | dev->mode_config.path_property = dev_path; | ||
1349 | |||
1350 | dev->mode_config.tile_property = drm_property_create(dev, | ||
1351 | DRM_MODE_PROP_BLOB | | ||
1352 | DRM_MODE_PROP_IMMUTABLE, | ||
1353 | "TILE", 0); | ||
1354 | 1365 | ||
1355 | return 0; | 1366 | prop = drm_property_create(dev, |
1356 | } | 1367 | DRM_MODE_PROP_BLOB | |
1368 | DRM_MODE_PROP_IMMUTABLE, | ||
1369 | "PATH", 0); | ||
1370 | if (!prop) | ||
1371 | return -ENOMEM; | ||
1372 | dev->mode_config.path_property = prop; | ||
1357 | 1373 | ||
1358 | static int drm_mode_create_standard_plane_properties(struct drm_device *dev) | 1374 | prop = drm_property_create(dev, |
1359 | { | 1375 | DRM_MODE_PROP_BLOB | |
1360 | struct drm_property *type; | 1376 | DRM_MODE_PROP_IMMUTABLE, |
1377 | "TILE", 0); | ||
1378 | if (!prop) | ||
1379 | return -ENOMEM; | ||
1380 | dev->mode_config.tile_property = prop; | ||
1361 | 1381 | ||
1362 | /* | 1382 | prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, |
1363 | * Standard properties (apply to all planes) | ||
1364 | */ | ||
1365 | type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, | ||
1366 | "type", drm_plane_type_enum_list, | 1383 | "type", drm_plane_type_enum_list, |
1367 | ARRAY_SIZE(drm_plane_type_enum_list)); | 1384 | ARRAY_SIZE(drm_plane_type_enum_list)); |
1368 | dev->mode_config.plane_type_property = type; | 1385 | if (!prop) |
1386 | return -ENOMEM; | ||
1387 | dev->mode_config.plane_type_property = prop; | ||
1388 | |||
1389 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
1390 | "SRC_X", 0, UINT_MAX); | ||
1391 | if (!prop) | ||
1392 | return -ENOMEM; | ||
1393 | dev->mode_config.prop_src_x = prop; | ||
1394 | |||
1395 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
1396 | "SRC_Y", 0, UINT_MAX); | ||
1397 | if (!prop) | ||
1398 | return -ENOMEM; | ||
1399 | dev->mode_config.prop_src_y = prop; | ||
1400 | |||
1401 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
1402 | "SRC_W", 0, UINT_MAX); | ||
1403 | if (!prop) | ||
1404 | return -ENOMEM; | ||
1405 | dev->mode_config.prop_src_w = prop; | ||
1406 | |||
1407 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
1408 | "SRC_H", 0, UINT_MAX); | ||
1409 | if (!prop) | ||
1410 | return -ENOMEM; | ||
1411 | dev->mode_config.prop_src_h = prop; | ||
1412 | |||
1413 | prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, | ||
1414 | "CRTC_X", INT_MIN, INT_MAX); | ||
1415 | if (!prop) | ||
1416 | return -ENOMEM; | ||
1417 | dev->mode_config.prop_crtc_x = prop; | ||
1418 | |||
1419 | prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, | ||
1420 | "CRTC_Y", INT_MIN, INT_MAX); | ||
1421 | if (!prop) | ||
1422 | return -ENOMEM; | ||
1423 | dev->mode_config.prop_crtc_y = prop; | ||
1424 | |||
1425 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
1426 | "CRTC_W", 0, INT_MAX); | ||
1427 | if (!prop) | ||
1428 | return -ENOMEM; | ||
1429 | dev->mode_config.prop_crtc_w = prop; | ||
1430 | |||
1431 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
1432 | "CRTC_H", 0, INT_MAX); | ||
1433 | if (!prop) | ||
1434 | return -ENOMEM; | ||
1435 | dev->mode_config.prop_crtc_h = prop; | ||
1436 | |||
1437 | prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, | ||
1438 | "FB_ID", DRM_MODE_OBJECT_FB); | ||
1439 | if (!prop) | ||
1440 | return -ENOMEM; | ||
1441 | dev->mode_config.prop_fb_id = prop; | ||
1442 | |||
1443 | prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, | ||
1444 | "CRTC_ID", DRM_MODE_OBJECT_CRTC); | ||
1445 | if (!prop) | ||
1446 | return -ENOMEM; | ||
1447 | dev->mode_config.prop_crtc_id = prop; | ||
1369 | 1448 | ||
1370 | return 0; | 1449 | return 0; |
1371 | } | 1450 | } |
@@ -1991,6 +2070,44 @@ static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *conne | |||
1991 | return connector->encoder; | 2070 | return connector->encoder; |
1992 | } | 2071 | } |
1993 | 2072 | ||
2073 | /* helper for getconnector and getproperties ioctls */ | ||
2074 | static int get_properties(struct drm_mode_object *obj, bool atomic, | ||
2075 | uint32_t __user *prop_ptr, uint64_t __user *prop_values, | ||
2076 | uint32_t *arg_count_props) | ||
2077 | { | ||
2078 | int props_count; | ||
2079 | int i, ret, copied; | ||
2080 | |||
2081 | props_count = obj->properties->count; | ||
2082 | if (!atomic) | ||
2083 | props_count -= obj->properties->atomic_count; | ||
2084 | |||
2085 | if ((*arg_count_props >= props_count) && props_count) { | ||
2086 | for (i = 0, copied = 0; copied < props_count; i++) { | ||
2087 | struct drm_property *prop = obj->properties->properties[i]; | ||
2088 | uint64_t val; | ||
2089 | |||
2090 | if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) | ||
2091 | continue; | ||
2092 | |||
2093 | ret = drm_object_property_get_value(obj, prop, &val); | ||
2094 | if (ret) | ||
2095 | return ret; | ||
2096 | |||
2097 | if (put_user(prop->base.id, prop_ptr + copied)) | ||
2098 | return -EFAULT; | ||
2099 | |||
2100 | if (put_user(val, prop_values + copied)) | ||
2101 | return -EFAULT; | ||
2102 | |||
2103 | copied++; | ||
2104 | } | ||
2105 | } | ||
2106 | *arg_count_props = props_count; | ||
2107 | |||
2108 | return 0; | ||
2109 | } | ||
2110 | |||
1994 | /** | 2111 | /** |
1995 | * drm_mode_getconnector - get connector configuration | 2112 | * drm_mode_getconnector - get connector configuration |
1996 | * @dev: drm device for the ioctl | 2113 | * @dev: drm device for the ioctl |
@@ -2012,15 +2129,12 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
2012 | struct drm_encoder *encoder; | 2129 | struct drm_encoder *encoder; |
2013 | struct drm_display_mode *mode; | 2130 | struct drm_display_mode *mode; |
2014 | int mode_count = 0; | 2131 | int mode_count = 0; |
2015 | int props_count = 0; | ||
2016 | int encoders_count = 0; | 2132 | int encoders_count = 0; |
2017 | int ret = 0; | 2133 | int ret = 0; |
2018 | int copied = 0; | 2134 | int copied = 0; |
2019 | int i; | 2135 | int i; |
2020 | struct drm_mode_modeinfo u_mode; | 2136 | struct drm_mode_modeinfo u_mode; |
2021 | struct drm_mode_modeinfo __user *mode_ptr; | 2137 | struct drm_mode_modeinfo __user *mode_ptr; |
2022 | uint32_t __user *prop_ptr; | ||
2023 | uint64_t __user *prop_values; | ||
2024 | uint32_t __user *encoder_ptr; | 2138 | uint32_t __user *encoder_ptr; |
2025 | 2139 | ||
2026 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 2140 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
@@ -2031,6 +2145,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
2031 | DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); | 2145 | DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); |
2032 | 2146 | ||
2033 | mutex_lock(&dev->mode_config.mutex); | 2147 | mutex_lock(&dev->mode_config.mutex); |
2148 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); | ||
2034 | 2149 | ||
2035 | connector = drm_connector_find(dev, out_resp->connector_id); | 2150 | connector = drm_connector_find(dev, out_resp->connector_id); |
2036 | if (!connector) { | 2151 | if (!connector) { |
@@ -2038,8 +2153,6 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
2038 | goto out; | 2153 | goto out; |
2039 | } | 2154 | } |
2040 | 2155 | ||
2041 | props_count = connector->properties.count; | ||
2042 | |||
2043 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) | 2156 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) |
2044 | if (connector->encoder_ids[i] != 0) | 2157 | if (connector->encoder_ids[i] != 0) |
2045 | encoders_count++; | 2158 | encoders_count++; |
@@ -2062,14 +2175,11 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
2062 | out_resp->mm_height = connector->display_info.height_mm; | 2175 | out_resp->mm_height = connector->display_info.height_mm; |
2063 | out_resp->subpixel = connector->display_info.subpixel_order; | 2176 | out_resp->subpixel = connector->display_info.subpixel_order; |
2064 | out_resp->connection = connector->status; | 2177 | out_resp->connection = connector->status; |
2065 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); | ||
2066 | |||
2067 | encoder = drm_connector_get_encoder(connector); | 2178 | encoder = drm_connector_get_encoder(connector); |
2068 | if (encoder) | 2179 | if (encoder) |
2069 | out_resp->encoder_id = encoder->base.id; | 2180 | out_resp->encoder_id = encoder->base.id; |
2070 | else | 2181 | else |
2071 | out_resp->encoder_id = 0; | 2182 | out_resp->encoder_id = 0; |
2072 | drm_modeset_unlock(&dev->mode_config.connection_mutex); | ||
2073 | 2183 | ||
2074 | /* | 2184 | /* |
2075 | * This ioctl is called twice, once to determine how much space is | 2185 | * This ioctl is called twice, once to determine how much space is |
@@ -2093,26 +2203,12 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
2093 | } | 2203 | } |
2094 | out_resp->count_modes = mode_count; | 2204 | out_resp->count_modes = mode_count; |
2095 | 2205 | ||
2096 | if ((out_resp->count_props >= props_count) && props_count) { | 2206 | ret = get_properties(&connector->base, file_priv->atomic, |
2097 | copied = 0; | 2207 | (uint32_t __user *)(unsigned long)(out_resp->props_ptr), |
2098 | prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr); | 2208 | (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), |
2099 | prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr); | 2209 | &out_resp->count_props); |
2100 | for (i = 0; i < connector->properties.count; i++) { | 2210 | if (ret) |
2101 | if (put_user(connector->properties.ids[i], | 2211 | goto out; |
2102 | prop_ptr + copied)) { | ||
2103 | ret = -EFAULT; | ||
2104 | goto out; | ||
2105 | } | ||
2106 | |||
2107 | if (put_user(connector->properties.values[i], | ||
2108 | prop_values + copied)) { | ||
2109 | ret = -EFAULT; | ||
2110 | goto out; | ||
2111 | } | ||
2112 | copied++; | ||
2113 | } | ||
2114 | } | ||
2115 | out_resp->count_props = props_count; | ||
2116 | 2212 | ||
2117 | if ((out_resp->count_encoders >= encoders_count) && encoders_count) { | 2213 | if ((out_resp->count_encoders >= encoders_count) && encoders_count) { |
2118 | copied = 0; | 2214 | copied = 0; |
@@ -2131,6 +2227,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
2131 | out_resp->count_encoders = encoders_count; | 2227 | out_resp->count_encoders = encoders_count; |
2132 | 2228 | ||
2133 | out: | 2229 | out: |
2230 | drm_modeset_unlock(&dev->mode_config.connection_mutex); | ||
2134 | mutex_unlock(&dev->mode_config.mutex); | 2231 | mutex_unlock(&dev->mode_config.mutex); |
2135 | 2232 | ||
2136 | return ret; | 2233 | return ret; |
@@ -3823,9 +3920,11 @@ void drm_object_attach_property(struct drm_mode_object *obj, | |||
3823 | return; | 3920 | return; |
3824 | } | 3921 | } |
3825 | 3922 | ||
3826 | obj->properties->ids[count] = property->base.id; | 3923 | obj->properties->properties[count] = property; |
3827 | obj->properties->values[count] = init_val; | 3924 | obj->properties->values[count] = init_val; |
3828 | obj->properties->count++; | 3925 | obj->properties->count++; |
3926 | if (property->flags & DRM_MODE_PROP_ATOMIC) | ||
3927 | obj->properties->atomic_count++; | ||
3829 | } | 3928 | } |
3830 | EXPORT_SYMBOL(drm_object_attach_property); | 3929 | EXPORT_SYMBOL(drm_object_attach_property); |
3831 | 3930 | ||
@@ -3848,7 +3947,7 @@ int drm_object_property_set_value(struct drm_mode_object *obj, | |||
3848 | int i; | 3947 | int i; |
3849 | 3948 | ||
3850 | for (i = 0; i < obj->properties->count; i++) { | 3949 | for (i = 0; i < obj->properties->count; i++) { |
3851 | if (obj->properties->ids[i] == property->base.id) { | 3950 | if (obj->properties->properties[i] == property) { |
3852 | obj->properties->values[i] = val; | 3951 | obj->properties->values[i] = val; |
3853 | return 0; | 3952 | return 0; |
3854 | } | 3953 | } |
@@ -3877,8 +3976,16 @@ int drm_object_property_get_value(struct drm_mode_object *obj, | |||
3877 | { | 3976 | { |
3878 | int i; | 3977 | int i; |
3879 | 3978 | ||
3979 | /* read-only properties bypass atomic mechanism and still store | ||
3980 | * their value in obj->properties->values[].. mostly to avoid | ||
3981 | * having to deal w/ EDID and similar props in atomic paths: | ||
3982 | */ | ||
3983 | if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) && | ||
3984 | !(property->flags & DRM_MODE_PROP_IMMUTABLE)) | ||
3985 | return drm_atomic_get_property(obj, property, val); | ||
3986 | |||
3880 | for (i = 0; i < obj->properties->count; i++) { | 3987 | for (i = 0; i < obj->properties->count; i++) { |
3881 | if (obj->properties->ids[i] == property->base.id) { | 3988 | if (obj->properties->properties[i] == property) { |
3882 | *val = obj->properties->values[i]; | 3989 | *val = obj->properties->values[i]; |
3883 | return 0; | 3990 | return 0; |
3884 | } | 3991 | } |
@@ -4194,14 +4301,24 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, | |||
4194 | } | 4301 | } |
4195 | EXPORT_SYMBOL(drm_mode_connector_update_edid_property); | 4302 | EXPORT_SYMBOL(drm_mode_connector_update_edid_property); |
4196 | 4303 | ||
4197 | static bool drm_property_change_is_valid(struct drm_property *property, | 4304 | /* Some properties could refer to dynamic refcnt'd objects, or things that |
4198 | uint64_t value) | 4305 | * need special locking to handle lifetime issues (ie. to ensure the prop |
4306 | * value doesn't become invalid part way through the property update due to | ||
4307 | * race). The value returned by reference via 'obj' should be passed back | ||
4308 | * to drm_property_change_valid_put() after the property is set (and the | ||
4309 | * object to which the property is attached has a chance to take it's own | ||
4310 | * reference). | ||
4311 | */ | ||
4312 | bool drm_property_change_valid_get(struct drm_property *property, | ||
4313 | uint64_t value, struct drm_mode_object **ref) | ||
4199 | { | 4314 | { |
4200 | int i; | 4315 | int i; |
4201 | 4316 | ||
4202 | if (property->flags & DRM_MODE_PROP_IMMUTABLE) | 4317 | if (property->flags & DRM_MODE_PROP_IMMUTABLE) |
4203 | return false; | 4318 | return false; |
4204 | 4319 | ||
4320 | *ref = NULL; | ||
4321 | |||
4205 | if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { | 4322 | if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { |
4206 | if (value < property->values[0] || value > property->values[1]) | 4323 | if (value < property->values[0] || value > property->values[1]) |
4207 | return false; | 4324 | return false; |
@@ -4223,20 +4340,29 @@ static bool drm_property_change_is_valid(struct drm_property *property, | |||
4223 | /* Only the driver knows */ | 4340 | /* Only the driver knows */ |
4224 | return true; | 4341 | return true; |
4225 | } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { | 4342 | } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { |
4226 | struct drm_mode_object *obj; | ||
4227 | |||
4228 | /* a zero value for an object property translates to null: */ | 4343 | /* a zero value for an object property translates to null: */ |
4229 | if (value == 0) | 4344 | if (value == 0) |
4230 | return true; | 4345 | return true; |
4231 | /* | 4346 | |
4232 | * NOTE: use _object_find() directly to bypass restriction on | 4347 | /* handle refcnt'd objects specially: */ |
4233 | * looking up refcnt'd objects (ie. fb's). For a refcnt'd | 4348 | if (property->values[0] == DRM_MODE_OBJECT_FB) { |
4234 | * object this could race against object finalization, so it | 4349 | struct drm_framebuffer *fb; |
4235 | * simply tells us that the object *was* valid. Which is good | 4350 | fb = drm_framebuffer_lookup(property->dev, value); |
4236 | * enough. | 4351 | if (fb) { |
4237 | */ | 4352 | *ref = &fb->base; |
4238 | obj = _object_find(property->dev, value, property->values[0]); | 4353 | return true; |
4239 | return obj != NULL; | 4354 | } else { |
4355 | return false; | ||
4356 | } | ||
4357 | } else { | ||
4358 | return _object_find(property->dev, value, property->values[0]) != NULL; | ||
4359 | } | ||
4360 | } else { | ||
4361 | int i; | ||
4362 | for (i = 0; i < property->num_values; i++) | ||
4363 | if (property->values[i] == value) | ||
4364 | return true; | ||
4365 | return false; | ||
4240 | } | 4366 | } |
4241 | 4367 | ||
4242 | for (i = 0; i < property->num_values; i++) | 4368 | for (i = 0; i < property->num_values; i++) |
@@ -4245,6 +4371,18 @@ static bool drm_property_change_is_valid(struct drm_property *property, | |||
4245 | return false; | 4371 | return false; |
4246 | } | 4372 | } |
4247 | 4373 | ||
4374 | void drm_property_change_valid_put(struct drm_property *property, | ||
4375 | struct drm_mode_object *ref) | ||
4376 | { | ||
4377 | if (!ref) | ||
4378 | return; | ||
4379 | |||
4380 | if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { | ||
4381 | if (property->values[0] == DRM_MODE_OBJECT_FB) | ||
4382 | drm_framebuffer_unreference(obj_to_fb(ref)); | ||
4383 | } | ||
4384 | } | ||
4385 | |||
4248 | /** | 4386 | /** |
4249 | * drm_mode_connector_property_set_ioctl - set the current value of a connector property | 4387 | * drm_mode_connector_property_set_ioctl - set the current value of a connector property |
4250 | * @dev: DRM device | 4388 | * @dev: DRM device |
@@ -4360,11 +4498,6 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, | |||
4360 | struct drm_mode_obj_get_properties *arg = data; | 4498 | struct drm_mode_obj_get_properties *arg = data; |
4361 | struct drm_mode_object *obj; | 4499 | struct drm_mode_object *obj; |
4362 | int ret = 0; | 4500 | int ret = 0; |
4363 | int i; | ||
4364 | int copied = 0; | ||
4365 | int props_count = 0; | ||
4366 | uint32_t __user *props_ptr; | ||
4367 | uint64_t __user *prop_values_ptr; | ||
4368 | 4501 | ||
4369 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 4502 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
4370 | return -EINVAL; | 4503 | return -EINVAL; |
@@ -4381,30 +4514,11 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, | |||
4381 | goto out; | 4514 | goto out; |
4382 | } | 4515 | } |
4383 | 4516 | ||
4384 | props_count = obj->properties->count; | 4517 | ret = get_properties(obj, file_priv->atomic, |
4518 | (uint32_t __user *)(unsigned long)(arg->props_ptr), | ||
4519 | (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), | ||
4520 | &arg->count_props); | ||
4385 | 4521 | ||
4386 | /* This ioctl is called twice, once to determine how much space is | ||
4387 | * needed, and the 2nd time to fill it. */ | ||
4388 | if ((arg->count_props >= props_count) && props_count) { | ||
4389 | copied = 0; | ||
4390 | props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr); | ||
4391 | prop_values_ptr = (uint64_t __user *)(unsigned long) | ||
4392 | (arg->prop_values_ptr); | ||
4393 | for (i = 0; i < props_count; i++) { | ||
4394 | if (put_user(obj->properties->ids[i], | ||
4395 | props_ptr + copied)) { | ||
4396 | ret = -EFAULT; | ||
4397 | goto out; | ||
4398 | } | ||
4399 | if (put_user(obj->properties->values[i], | ||
4400 | prop_values_ptr + copied)) { | ||
4401 | ret = -EFAULT; | ||
4402 | goto out; | ||
4403 | } | ||
4404 | copied++; | ||
4405 | } | ||
4406 | } | ||
4407 | arg->count_props = props_count; | ||
4408 | out: | 4522 | out: |
4409 | drm_modeset_unlock_all(dev); | 4523 | drm_modeset_unlock_all(dev); |
4410 | return ret; | 4524 | return ret; |
@@ -4433,8 +4547,8 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | |||
4433 | struct drm_mode_object *arg_obj; | 4547 | struct drm_mode_object *arg_obj; |
4434 | struct drm_mode_object *prop_obj; | 4548 | struct drm_mode_object *prop_obj; |
4435 | struct drm_property *property; | 4549 | struct drm_property *property; |
4436 | int ret = -EINVAL; | 4550 | int i, ret = -EINVAL; |
4437 | int i; | 4551 | struct drm_mode_object *ref; |
4438 | 4552 | ||
4439 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 4553 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
4440 | return -EINVAL; | 4554 | return -EINVAL; |
@@ -4450,7 +4564,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | |||
4450 | goto out; | 4564 | goto out; |
4451 | 4565 | ||
4452 | for (i = 0; i < arg_obj->properties->count; i++) | 4566 | for (i = 0; i < arg_obj->properties->count; i++) |
4453 | if (arg_obj->properties->ids[i] == arg->prop_id) | 4567 | if (arg_obj->properties->properties[i]->base.id == arg->prop_id) |
4454 | break; | 4568 | break; |
4455 | 4569 | ||
4456 | if (i == arg_obj->properties->count) | 4570 | if (i == arg_obj->properties->count) |
@@ -4464,7 +4578,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | |||
4464 | } | 4578 | } |
4465 | property = obj_to_property(prop_obj); | 4579 | property = obj_to_property(prop_obj); |
4466 | 4580 | ||
4467 | if (!drm_property_change_is_valid(property, arg->value)) | 4581 | if (!drm_property_change_valid_get(property, arg->value, &ref)) |
4468 | goto out; | 4582 | goto out; |
4469 | 4583 | ||
4470 | switch (arg_obj->type) { | 4584 | switch (arg_obj->type) { |
@@ -4481,6 +4595,8 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | |||
4481 | break; | 4595 | break; |
4482 | } | 4596 | } |
4483 | 4597 | ||
4598 | drm_property_change_valid_put(property, ref); | ||
4599 | |||
4484 | out: | 4600 | out: |
4485 | drm_modeset_unlock_all(dev); | 4601 | drm_modeset_unlock_all(dev); |
4486 | return ret; | 4602 | return ret; |
@@ -5225,8 +5341,7 @@ void drm_mode_config_init(struct drm_device *dev) | |||
5225 | idr_init(&dev->mode_config.tile_idr); | 5341 | idr_init(&dev->mode_config.tile_idr); |
5226 | 5342 | ||
5227 | drm_modeset_lock_all(dev); | 5343 | drm_modeset_lock_all(dev); |
5228 | drm_mode_create_standard_connector_properties(dev); | 5344 | drm_mode_create_standard_properties(dev); |
5229 | drm_mode_create_standard_plane_properties(dev); | ||
5230 | drm_modeset_unlock_all(dev); | 5345 | drm_modeset_unlock_all(dev); |
5231 | 5346 | ||
5232 | /* Just to be sure */ | 5347 | /* Just to be sure */ |
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index d552708409de..b1979e7bdc88 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -946,6 +946,7 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod | |||
946 | crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL); | 946 | crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL); |
947 | if (!crtc_state) | 947 | if (!crtc_state) |
948 | return -ENOMEM; | 948 | return -ENOMEM; |
949 | crtc_state->crtc = crtc; | ||
949 | 950 | ||
950 | crtc_state->enable = true; | 951 | crtc_state->enable = true; |
951 | crtc_state->planes_changed = true; | 952 | crtc_state->planes_changed = true; |
@@ -1005,6 +1006,7 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | |||
1005 | plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); | 1006 | plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); |
1006 | if (!plane_state) | 1007 | if (!plane_state) |
1007 | return -ENOMEM; | 1008 | return -ENOMEM; |
1009 | plane_state->plane = plane; | ||
1008 | 1010 | ||
1009 | plane_state->crtc = crtc; | 1011 | plane_state->crtc = crtc; |
1010 | drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb); | 1012 | drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb); |
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index a2945ee6d675..247dc8b62564 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h | |||
@@ -36,3 +36,9 @@ int drm_mode_object_get(struct drm_device *dev, | |||
36 | void drm_mode_object_put(struct drm_device *dev, | 36 | void drm_mode_object_put(struct drm_device *dev, |
37 | struct drm_mode_object *object); | 37 | struct drm_mode_object *object); |
38 | 38 | ||
39 | /* drm_atomic.c */ | ||
40 | int drm_atomic_get_property(struct drm_mode_object *obj, | ||
41 | struct drm_property *property, uint64_t *val); | ||
42 | int drm_mode_atomic_ioctl(struct drm_device *dev, | ||
43 | void *data, struct drm_file *file_priv); | ||
44 | |||
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 4f41377b0b80..d51213464672 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c | |||
@@ -40,15 +40,19 @@ | |||
40 | unsigned int drm_debug = 0; /* 1 to enable debug output */ | 40 | unsigned int drm_debug = 0; /* 1 to enable debug output */ |
41 | EXPORT_SYMBOL(drm_debug); | 41 | EXPORT_SYMBOL(drm_debug); |
42 | 42 | ||
43 | bool drm_atomic = 0; | ||
44 | |||
43 | MODULE_AUTHOR(CORE_AUTHOR); | 45 | MODULE_AUTHOR(CORE_AUTHOR); |
44 | MODULE_DESCRIPTION(CORE_DESC); | 46 | MODULE_DESCRIPTION(CORE_DESC); |
45 | MODULE_LICENSE("GPL and additional rights"); | 47 | MODULE_LICENSE("GPL and additional rights"); |
46 | MODULE_PARM_DESC(debug, "Enable debug output"); | 48 | MODULE_PARM_DESC(debug, "Enable debug output"); |
49 | MODULE_PARM_DESC(atomic, "Enable experimental atomic KMS API"); | ||
47 | MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)"); | 50 | MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)"); |
48 | MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); | 51 | MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); |
49 | MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps"); | 52 | MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps"); |
50 | 53 | ||
51 | module_param_named(debug, drm_debug, int, 0600); | 54 | module_param_named(debug, drm_debug, int, 0600); |
55 | module_param_named_unsafe(atomic, drm_atomic, bool, 0600); | ||
52 | 56 | ||
53 | static DEFINE_SPINLOCK(drm_minor_lock); | 57 | static DEFINE_SPINLOCK(drm_minor_lock); |
54 | static struct idr drm_minors_idr; | 58 | static struct idr drm_minors_idr; |
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 00587a1e3c83..3785d66721f2 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <drm/drm_core.h> | 32 | #include <drm/drm_core.h> |
33 | #include "drm_legacy.h" | 33 | #include "drm_legacy.h" |
34 | #include "drm_internal.h" | 34 | #include "drm_internal.h" |
35 | #include "drm_crtc_internal.h" | ||
35 | 36 | ||
36 | #include <linux/pci.h> | 37 | #include <linux/pci.h> |
37 | #include <linux/export.h> | 38 | #include <linux/export.h> |
@@ -345,6 +346,17 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
345 | return -EINVAL; | 346 | return -EINVAL; |
346 | file_priv->universal_planes = req->value; | 347 | file_priv->universal_planes = req->value; |
347 | break; | 348 | break; |
349 | case DRM_CLIENT_CAP_ATOMIC: | ||
350 | /* for now, hide behind experimental drm.atomic moduleparam */ | ||
351 | if (!drm_atomic) | ||
352 | return -EINVAL; | ||
353 | if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) | ||
354 | return -EINVAL; | ||
355 | if (req->value > 1) | ||
356 | return -EINVAL; | ||
357 | file_priv->atomic = req->value; | ||
358 | file_priv->universal_planes = req->value; | ||
359 | break; | ||
348 | default: | 360 | default: |
349 | return -EINVAL; | 361 | return -EINVAL; |
350 | } | 362 | } |
@@ -620,6 +632,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { | |||
620 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 632 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
621 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 633 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
622 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 634 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), |
635 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | ||
623 | }; | 636 | }; |
624 | 637 | ||
625 | #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) | 638 | #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) |
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 391dfb7d1086..f24c4cfe674b 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c | |||
@@ -523,6 +523,7 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, | |||
523 | plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); | 523 | plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); |
524 | if (!plane_state) | 524 | if (!plane_state) |
525 | return -ENOMEM; | 525 | return -ENOMEM; |
526 | plane_state->plane = plane; | ||
526 | 527 | ||
527 | plane_state->crtc = crtc; | 528 | plane_state->crtc = crtc; |
528 | drm_atomic_set_fb_for_plane(plane_state, fb); | 529 | drm_atomic_set_fb_for_plane(plane_state, fb); |
@@ -569,6 +570,7 @@ int drm_plane_helper_disable(struct drm_plane *plane) | |||
569 | plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); | 570 | plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); |
570 | if (!plane_state) | 571 | if (!plane_state) |
571 | return -ENOMEM; | 572 | return -ENOMEM; |
573 | plane_state->plane = plane; | ||
572 | 574 | ||
573 | plane_state->crtc = NULL; | 575 | plane_state->crtc = NULL; |
574 | drm_atomic_set_fb_for_plane(plane_state, NULL); | 576 | drm_atomic_set_fb_for_plane(plane_state, NULL); |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 26e5fdea6594..fc76f630e5b1 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | |||
@@ -113,6 +113,7 @@ static void mdp5_plane_reset(struct drm_plane *plane) | |||
113 | } else { | 113 | } else { |
114 | mdp5_state->zpos = 1 + drm_plane_index(plane); | 114 | mdp5_state->zpos = 1 + drm_plane_index(plane); |
115 | } | 115 | } |
116 | mdp5_state->base.plane = plane; | ||
116 | 117 | ||
117 | plane->state = &mdp5_state->base; | 118 | plane->state = &mdp5_state->base; |
118 | } | 119 | } |
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 191968256c58..2c396540e279 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c | |||
@@ -127,6 +127,26 @@ static void add_fb(struct msm_commit *c, struct drm_framebuffer *fb) | |||
127 | } | 127 | } |
128 | 128 | ||
129 | 129 | ||
130 | int msm_atomic_check(struct drm_device *dev, | ||
131 | struct drm_atomic_state *state) | ||
132 | { | ||
133 | int ret; | ||
134 | |||
135 | /* | ||
136 | * msm ->atomic_check can update ->mode_changed for pixel format | ||
137 | * changes, hence must be run before we check the modeset changes. | ||
138 | */ | ||
139 | ret = drm_atomic_helper_check_planes(dev, state); | ||
140 | if (ret) | ||
141 | return ret; | ||
142 | |||
143 | ret = drm_atomic_helper_check_modeset(dev, state); | ||
144 | if (ret) | ||
145 | return ret; | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | |||
130 | /** | 150 | /** |
131 | * drm_atomic_helper_commit - commit validated state object | 151 | * drm_atomic_helper_commit - commit validated state object |
132 | * @dev: DRM device | 152 | * @dev: DRM device |
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 9a61546a0b05..f1ebedde6346 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c | |||
@@ -29,7 +29,7 @@ static void msm_fb_output_poll_changed(struct drm_device *dev) | |||
29 | static const struct drm_mode_config_funcs mode_config_funcs = { | 29 | static const struct drm_mode_config_funcs mode_config_funcs = { |
30 | .fb_create = msm_framebuffer_create, | 30 | .fb_create = msm_framebuffer_create, |
31 | .output_poll_changed = msm_fb_output_poll_changed, | 31 | .output_poll_changed = msm_fb_output_poll_changed, |
32 | .atomic_check = drm_atomic_helper_check, | 32 | .atomic_check = msm_atomic_check, |
33 | .atomic_commit = msm_atomic_commit, | 33 | .atomic_commit = msm_atomic_commit, |
34 | }; | 34 | }; |
35 | 35 | ||
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index b69ef2d5a26c..22e5391a7ce8 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h | |||
@@ -148,6 +148,8 @@ void __msm_fence_worker(struct work_struct *work); | |||
148 | (_cb)->func = _func; \ | 148 | (_cb)->func = _func; \ |
149 | } while (0) | 149 | } while (0) |
150 | 150 | ||
151 | int msm_atomic_check(struct drm_device *dev, | ||
152 | struct drm_atomic_state *state); | ||
151 | int msm_atomic_commit(struct drm_device *dev, | 153 | int msm_atomic_commit(struct drm_device *dev, |
152 | struct drm_atomic_state *state, bool async); | 154 | struct drm_atomic_state *state, bool async); |
153 | 155 | ||