diff options
-rw-r--r-- | drivers/gpu/drm/drm_atomic.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_atomic_helper.c | 181 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 76 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_plane_helper.c | 14 | ||||
-rw-r--r-- | include/drm/drm_atomic_helper.h | 2 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 7 | ||||
-rw-r--r-- | include/drm/drm_crtc_helper.h | 21 |
7 files changed, 301 insertions, 21 deletions
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 4c5c9c3899e0..c2e9c5283136 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c | |||
@@ -134,6 +134,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state) | |||
134 | 134 | ||
135 | connector->funcs->atomic_destroy_state(connector, | 135 | connector->funcs->atomic_destroy_state(connector, |
136 | state->connector_states[i]); | 136 | state->connector_states[i]); |
137 | state->connector_states[i] = NULL; | ||
137 | } | 138 | } |
138 | 139 | ||
139 | for (i = 0; i < config->num_crtc; i++) { | 140 | for (i = 0; i < config->num_crtc; i++) { |
@@ -144,6 +145,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state) | |||
144 | 145 | ||
145 | crtc->funcs->atomic_destroy_state(crtc, | 146 | crtc->funcs->atomic_destroy_state(crtc, |
146 | state->crtc_states[i]); | 147 | state->crtc_states[i]); |
148 | state->crtc_states[i] = NULL; | ||
147 | } | 149 | } |
148 | 150 | ||
149 | for (i = 0; i < config->num_total_plane; i++) { | 151 | for (i = 0; i < config->num_total_plane; i++) { |
@@ -154,6 +156,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state) | |||
154 | 156 | ||
155 | plane->funcs->atomic_destroy_state(plane, | 157 | plane->funcs->atomic_destroy_state(plane, |
156 | state->plane_states[i]); | 158 | state->plane_states[i]); |
159 | state->plane_states[i] = NULL; | ||
157 | } | 160 | } |
158 | } | 161 | } |
159 | EXPORT_SYMBOL(drm_atomic_state_clear); | 162 | EXPORT_SYMBOL(drm_atomic_state_clear); |
@@ -241,7 +244,13 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, | |||
241 | struct drm_crtc_state *state, struct drm_property *property, | 244 | struct drm_crtc_state *state, struct drm_property *property, |
242 | uint64_t val) | 245 | uint64_t val) |
243 | { | 246 | { |
244 | if (crtc->funcs->atomic_set_property) | 247 | struct drm_device *dev = crtc->dev; |
248 | struct drm_mode_config *config = &dev->mode_config; | ||
249 | |||
250 | /* FIXME: Mode prop is missing, which also controls ->enable. */ | ||
251 | if (property == config->prop_active) { | ||
252 | state->active = val; | ||
253 | } else if (crtc->funcs->atomic_set_property) | ||
245 | return crtc->funcs->atomic_set_property(crtc, state, property, val); | 254 | return crtc->funcs->atomic_set_property(crtc, state, property, val); |
246 | return -EINVAL; | 255 | return -EINVAL; |
247 | } | 256 | } |
@@ -282,6 +291,13 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc, | |||
282 | * | 291 | * |
283 | * TODO: Add generic modeset state checks once we support those. | 292 | * TODO: Add generic modeset state checks once we support those. |
284 | */ | 293 | */ |
294 | |||
295 | if (state->active && !state->enable) { | ||
296 | DRM_DEBUG_KMS("[CRTC:%d] active without enabled\n", | ||
297 | crtc->base.id); | ||
298 | return -EINVAL; | ||
299 | } | ||
300 | |||
285 | return 0; | 301 | return 0; |
286 | } | 302 | } |
287 | 303 | ||
@@ -978,7 +994,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) | |||
978 | if (!crtc) | 994 | if (!crtc) |
979 | continue; | 995 | continue; |
980 | 996 | ||
981 | if (crtc_state->mode_changed) { | 997 | if (crtc_state->mode_changed || |
998 | crtc_state->active_changed) { | ||
982 | DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n", | 999 | DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n", |
983 | crtc->base.id); | 1000 | crtc->base.id); |
984 | return -EINVAL; | 1001 | return -EINVAL; |
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 24c44c24dabe..7e3a52b97c7d 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
@@ -339,6 +339,12 @@ mode_fixup(struct drm_atomic_state *state) | |||
339 | return 0; | 339 | return 0; |
340 | } | 340 | } |
341 | 341 | ||
342 | static bool | ||
343 | needs_modeset(struct drm_crtc_state *state) | ||
344 | { | ||
345 | return state->mode_changed || state->active_changed; | ||
346 | } | ||
347 | |||
342 | /** | 348 | /** |
343 | * drm_atomic_helper_check - validate state object for modeset changes | 349 | * drm_atomic_helper_check - validate state object for modeset changes |
344 | * @dev: DRM device | 350 | * @dev: DRM device |
@@ -413,12 +419,27 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, | |||
413 | crtc = state->crtcs[i]; | 419 | crtc = state->crtcs[i]; |
414 | crtc_state = state->crtc_states[i]; | 420 | crtc_state = state->crtc_states[i]; |
415 | 421 | ||
416 | if (!crtc || !crtc_state->mode_changed) | 422 | if (!crtc) |
423 | continue; | ||
424 | |||
425 | /* | ||
426 | * We must set ->active_changed after walking connectors for | ||
427 | * otherwise an update that only changes active would result in | ||
428 | * a full modeset because update_connector_routing force that. | ||
429 | */ | ||
430 | if (crtc->state->active != crtc_state->active) { | ||
431 | DRM_DEBUG_KMS("[CRTC:%d] active changed\n", | ||
432 | crtc->base.id); | ||
433 | crtc_state->active_changed = true; | ||
434 | } | ||
435 | |||
436 | if (!needs_modeset(crtc_state)) | ||
417 | continue; | 437 | continue; |
418 | 438 | ||
419 | DRM_DEBUG_KMS("[CRTC:%d] needs full modeset, enable: %c\n", | 439 | DRM_DEBUG_KMS("[CRTC:%d] needs all connectors, enable: %c, active: %c\n", |
420 | crtc->base.id, | 440 | crtc->base.id, |
421 | crtc_state->enable ? 'y' : 'n'); | 441 | crtc_state->enable ? 'y' : 'n', |
442 | crtc_state->active ? 'y' : 'n'); | ||
422 | 443 | ||
423 | ret = drm_atomic_add_affected_connectors(state, crtc); | 444 | ret = drm_atomic_add_affected_connectors(state, crtc); |
424 | if (ret != 0) | 445 | if (ret != 0) |
@@ -554,6 +575,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) | |||
554 | struct drm_connector *connector; | 575 | struct drm_connector *connector; |
555 | struct drm_encoder_helper_funcs *funcs; | 576 | struct drm_encoder_helper_funcs *funcs; |
556 | struct drm_encoder *encoder; | 577 | struct drm_encoder *encoder; |
578 | struct drm_crtc_state *old_crtc_state; | ||
557 | 579 | ||
558 | old_conn_state = old_state->connector_states[i]; | 580 | old_conn_state = old_state->connector_states[i]; |
559 | connector = old_state->connectors[i]; | 581 | connector = old_state->connectors[i]; |
@@ -563,6 +585,11 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) | |||
563 | if (!old_conn_state || !old_conn_state->crtc) | 585 | if (!old_conn_state || !old_conn_state->crtc) |
564 | continue; | 586 | continue; |
565 | 587 | ||
588 | old_crtc_state = old_state->crtc_states[drm_crtc_index(old_conn_state->crtc)]; | ||
589 | |||
590 | if (!old_crtc_state->active) | ||
591 | continue; | ||
592 | |||
566 | encoder = old_conn_state->best_encoder; | 593 | encoder = old_conn_state->best_encoder; |
567 | 594 | ||
568 | /* We shouldn't get this far if we didn't previously have | 595 | /* We shouldn't get this far if we didn't previously have |
@@ -573,6 +600,9 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) | |||
573 | 600 | ||
574 | funcs = encoder->helper_private; | 601 | funcs = encoder->helper_private; |
575 | 602 | ||
603 | DRM_DEBUG_KMS("disabling [ENCODER:%d:%s]\n", | ||
604 | encoder->base.id, encoder->name); | ||
605 | |||
576 | /* | 606 | /* |
577 | * Each encoder has at most one connector (since we always steal | 607 | * Each encoder has at most one connector (since we always steal |
578 | * it away), so we won't call call disable hooks twice. | 608 | * it away), so we won't call call disable hooks twice. |
@@ -581,7 +611,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) | |||
581 | encoder->bridge->funcs->disable(encoder->bridge); | 611 | encoder->bridge->funcs->disable(encoder->bridge); |
582 | 612 | ||
583 | /* Right function depends upon target state. */ | 613 | /* Right function depends upon target state. */ |
584 | if (connector->state->crtc) | 614 | if (connector->state->crtc && funcs->prepare) |
585 | funcs->prepare(encoder); | 615 | funcs->prepare(encoder); |
586 | else if (funcs->disable) | 616 | else if (funcs->disable) |
587 | funcs->disable(encoder); | 617 | funcs->disable(encoder); |
@@ -595,17 +625,26 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) | |||
595 | for (i = 0; i < ncrtcs; i++) { | 625 | for (i = 0; i < ncrtcs; i++) { |
596 | struct drm_crtc_helper_funcs *funcs; | 626 | struct drm_crtc_helper_funcs *funcs; |
597 | struct drm_crtc *crtc; | 627 | struct drm_crtc *crtc; |
628 | struct drm_crtc_state *old_crtc_state; | ||
598 | 629 | ||
599 | crtc = old_state->crtcs[i]; | 630 | crtc = old_state->crtcs[i]; |
631 | old_crtc_state = old_state->crtc_states[i]; | ||
600 | 632 | ||
601 | /* Shut down everything that needs a full modeset. */ | 633 | /* Shut down everything that needs a full modeset. */ |
602 | if (!crtc || !crtc->state->mode_changed) | 634 | if (!crtc || !needs_modeset(crtc->state)) |
635 | continue; | ||
636 | |||
637 | if (!old_crtc_state->active) | ||
603 | continue; | 638 | continue; |
604 | 639 | ||
605 | funcs = crtc->helper_private; | 640 | funcs = crtc->helper_private; |
606 | 641 | ||
642 | DRM_DEBUG_KMS("disabling [CRTC:%d]\n", | ||
643 | crtc->base.id); | ||
644 | |||
645 | |||
607 | /* Right function depends upon target state. */ | 646 | /* Right function depends upon target state. */ |
608 | if (crtc->state->enable) | 647 | if (crtc->state->enable && funcs->prepare) |
609 | funcs->prepare(crtc); | 648 | funcs->prepare(crtc); |
610 | else if (funcs->disable) | 649 | else if (funcs->disable) |
611 | funcs->disable(crtc); | 650 | funcs->disable(crtc); |
@@ -684,8 +723,12 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) | |||
684 | 723 | ||
685 | funcs = crtc->helper_private; | 724 | funcs = crtc->helper_private; |
686 | 725 | ||
687 | if (crtc->state->enable) | 726 | if (crtc->state->enable) { |
727 | DRM_DEBUG_KMS("modeset on [CRTC:%d]\n", | ||
728 | crtc->base.id); | ||
729 | |||
688 | funcs->mode_set_nofb(crtc); | 730 | funcs->mode_set_nofb(crtc); |
731 | } | ||
689 | } | 732 | } |
690 | 733 | ||
691 | for (i = 0; i < old_state->num_connector; i++) { | 734 | for (i = 0; i < old_state->num_connector; i++) { |
@@ -706,6 +749,12 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) | |||
706 | mode = &new_crtc_state->mode; | 749 | mode = &new_crtc_state->mode; |
707 | adjusted_mode = &new_crtc_state->adjusted_mode; | 750 | adjusted_mode = &new_crtc_state->adjusted_mode; |
708 | 751 | ||
752 | if (!new_crtc_state->mode_changed) | ||
753 | continue; | ||
754 | |||
755 | DRM_DEBUG_KMS("modeset on [ENCODER:%d:%s]\n", | ||
756 | encoder->base.id, encoder->name); | ||
757 | |||
709 | /* | 758 | /* |
710 | * Each encoder has at most one connector (since we always steal | 759 | * Each encoder has at most one connector (since we always steal |
711 | * it away), so we won't call call mode_set hooks twice. | 760 | * it away), so we won't call call mode_set hooks twice. |
@@ -758,13 +807,23 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev, | |||
758 | crtc = old_state->crtcs[i]; | 807 | crtc = old_state->crtcs[i]; |
759 | 808 | ||
760 | /* Need to filter out CRTCs where only planes change. */ | 809 | /* Need to filter out CRTCs where only planes change. */ |
761 | if (!crtc || !crtc->state->mode_changed) | 810 | if (!crtc || !needs_modeset(crtc->state)) |
811 | continue; | ||
812 | |||
813 | if (!crtc->state->active) | ||
762 | continue; | 814 | continue; |
763 | 815 | ||
764 | funcs = crtc->helper_private; | 816 | funcs = crtc->helper_private; |
765 | 817 | ||
766 | if (crtc->state->enable) | 818 | if (crtc->state->enable) { |
767 | funcs->commit(crtc); | 819 | DRM_DEBUG_KMS("enabling [CRTC:%d]\n", |
820 | crtc->base.id); | ||
821 | |||
822 | if (funcs->enable) | ||
823 | funcs->enable(crtc); | ||
824 | else | ||
825 | funcs->commit(crtc); | ||
826 | } | ||
768 | } | 827 | } |
769 | 828 | ||
770 | for (i = 0; i < old_state->num_connector; i++) { | 829 | for (i = 0; i < old_state->num_connector; i++) { |
@@ -777,9 +836,15 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev, | |||
777 | if (!connector || !connector->state->best_encoder) | 836 | if (!connector || !connector->state->best_encoder) |
778 | continue; | 837 | continue; |
779 | 838 | ||
839 | if (!connector->state->crtc->state->active) | ||
840 | continue; | ||
841 | |||
780 | encoder = connector->state->best_encoder; | 842 | encoder = connector->state->best_encoder; |
781 | funcs = encoder->helper_private; | 843 | funcs = encoder->helper_private; |
782 | 844 | ||
845 | DRM_DEBUG_KMS("enabling [ENCODER:%d:%s]\n", | ||
846 | encoder->base.id, encoder->name); | ||
847 | |||
783 | /* | 848 | /* |
784 | * Each encoder has at most one connector (since we always steal | 849 | * Each encoder has at most one connector (since we always steal |
785 | * it away), so we won't call call enable hooks twice. | 850 | * it away), so we won't call call enable hooks twice. |
@@ -787,7 +852,10 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev, | |||
787 | if (encoder->bridge) | 852 | if (encoder->bridge) |
788 | encoder->bridge->funcs->pre_enable(encoder->bridge); | 853 | encoder->bridge->funcs->pre_enable(encoder->bridge); |
789 | 854 | ||
790 | funcs->commit(encoder); | 855 | if (funcs->enable) |
856 | funcs->enable(encoder); | ||
857 | else | ||
858 | funcs->commit(encoder); | ||
791 | 859 | ||
792 | if (encoder->bridge) | 860 | if (encoder->bridge) |
793 | encoder->bridge->funcs->enable(encoder->bridge); | 861 | encoder->bridge->funcs->enable(encoder->bridge); |
@@ -877,6 +945,11 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, | |||
877 | if (!crtc->state->enable) | 945 | if (!crtc->state->enable) |
878 | continue; | 946 | continue; |
879 | 947 | ||
948 | /* Legacy cursor ioctls are completely unsynced, and userspace | ||
949 | * relies on that (by doing tons of cursor updates). */ | ||
950 | if (old_state->legacy_cursor_update) | ||
951 | continue; | ||
952 | |||
880 | if (!framebuffer_changed(dev, old_state, crtc)) | 953 | if (!framebuffer_changed(dev, old_state, crtc)) |
881 | continue; | 954 | continue; |
882 | 955 | ||
@@ -1310,6 +1383,9 @@ retry: | |||
1310 | if (ret != 0) | 1383 | if (ret != 0) |
1311 | goto fail; | 1384 | goto fail; |
1312 | 1385 | ||
1386 | if (plane == crtc->cursor) | ||
1387 | state->legacy_cursor_update = true; | ||
1388 | |||
1313 | /* Driver takes ownership of state on successful commit. */ | 1389 | /* Driver takes ownership of state on successful commit. */ |
1314 | return 0; | 1390 | return 0; |
1315 | fail: | 1391 | fail: |
@@ -1385,6 +1461,9 @@ retry: | |||
1385 | plane_state->src_h = 0; | 1461 | plane_state->src_h = 0; |
1386 | plane_state->src_w = 0; | 1462 | plane_state->src_w = 0; |
1387 | 1463 | ||
1464 | if (plane == plane->crtc->cursor) | ||
1465 | state->legacy_cursor_update = true; | ||
1466 | |||
1388 | ret = drm_atomic_commit(state); | 1467 | ret = drm_atomic_commit(state); |
1389 | if (ret != 0) | 1468 | if (ret != 0) |
1390 | goto fail; | 1469 | goto fail; |
@@ -1534,6 +1613,7 @@ retry: | |||
1534 | WARN_ON(set->num_connectors); | 1613 | WARN_ON(set->num_connectors); |
1535 | 1614 | ||
1536 | crtc_state->enable = false; | 1615 | crtc_state->enable = false; |
1616 | crtc_state->active = false; | ||
1537 | 1617 | ||
1538 | ret = drm_atomic_set_crtc_for_plane(primary_state, NULL); | 1618 | ret = drm_atomic_set_crtc_for_plane(primary_state, NULL); |
1539 | if (ret != 0) | 1619 | if (ret != 0) |
@@ -1548,6 +1628,7 @@ retry: | |||
1548 | WARN_ON(!set->num_connectors); | 1628 | WARN_ON(!set->num_connectors); |
1549 | 1629 | ||
1550 | crtc_state->enable = true; | 1630 | crtc_state->enable = true; |
1631 | crtc_state->active = true; | ||
1551 | drm_mode_copy(&crtc_state->mode, set->mode); | 1632 | drm_mode_copy(&crtc_state->mode, set->mode); |
1552 | 1633 | ||
1553 | ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); | 1634 | ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); |
@@ -1860,6 +1941,83 @@ backoff: | |||
1860 | EXPORT_SYMBOL(drm_atomic_helper_page_flip); | 1941 | EXPORT_SYMBOL(drm_atomic_helper_page_flip); |
1861 | 1942 | ||
1862 | /** | 1943 | /** |
1944 | * drm_atomic_helper_connector_dpms() - connector dpms helper implementation | ||
1945 | * @connector: affected connector | ||
1946 | * @mode: DPMS mode | ||
1947 | * | ||
1948 | * This is the main helper function provided by the atomic helper framework for | ||
1949 | * implementing the legacy DPMS connector interface. It computes the new desired | ||
1950 | * ->active state for the corresponding CRTC (if the connector is enabled) and | ||
1951 | * updates it. | ||
1952 | */ | ||
1953 | void drm_atomic_helper_connector_dpms(struct drm_connector *connector, | ||
1954 | int mode) | ||
1955 | { | ||
1956 | struct drm_mode_config *config = &connector->dev->mode_config; | ||
1957 | struct drm_atomic_state *state; | ||
1958 | struct drm_crtc_state *crtc_state; | ||
1959 | struct drm_crtc *crtc; | ||
1960 | struct drm_connector *tmp_connector; | ||
1961 | int ret; | ||
1962 | bool active = false; | ||
1963 | |||
1964 | if (mode != DRM_MODE_DPMS_ON) | ||
1965 | mode = DRM_MODE_DPMS_OFF; | ||
1966 | |||
1967 | connector->dpms = mode; | ||
1968 | crtc = connector->state->crtc; | ||
1969 | |||
1970 | if (!crtc) | ||
1971 | return; | ||
1972 | |||
1973 | /* FIXME: ->dpms has no return value so can't forward the -ENOMEM. */ | ||
1974 | state = drm_atomic_state_alloc(connector->dev); | ||
1975 | if (!state) | ||
1976 | return; | ||
1977 | |||
1978 | state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); | ||
1979 | retry: | ||
1980 | crtc_state = drm_atomic_get_crtc_state(state, crtc); | ||
1981 | if (IS_ERR(crtc_state)) | ||
1982 | return; | ||
1983 | |||
1984 | WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); | ||
1985 | |||
1986 | list_for_each_entry(tmp_connector, &config->connector_list, head) { | ||
1987 | if (connector->state->crtc != crtc) | ||
1988 | continue; | ||
1989 | |||
1990 | if (connector->dpms == DRM_MODE_DPMS_ON) { | ||
1991 | active = true; | ||
1992 | break; | ||
1993 | } | ||
1994 | } | ||
1995 | crtc_state->active = active; | ||
1996 | |||
1997 | ret = drm_atomic_commit(state); | ||
1998 | if (ret != 0) | ||
1999 | goto fail; | ||
2000 | |||
2001 | /* Driver takes ownership of state on successful async commit. */ | ||
2002 | return; | ||
2003 | fail: | ||
2004 | if (ret == -EDEADLK) | ||
2005 | goto backoff; | ||
2006 | |||
2007 | drm_atomic_state_free(state); | ||
2008 | |||
2009 | WARN(1, "Driver bug: Changing ->active failed with ret=%i\n", ret); | ||
2010 | |||
2011 | return; | ||
2012 | backoff: | ||
2013 | drm_atomic_state_clear(state); | ||
2014 | drm_atomic_legacy_backoff(state); | ||
2015 | |||
2016 | goto retry; | ||
2017 | } | ||
2018 | EXPORT_SYMBOL(drm_atomic_helper_connector_dpms); | ||
2019 | |||
2020 | /** | ||
1863 | * DOC: atomic state reset and initialization | 2021 | * DOC: atomic state reset and initialization |
1864 | * | 2022 | * |
1865 | * Both the drm core and the atomic helpers assume that there is always the full | 2023 | * Both the drm core and the atomic helpers assume that there is always the full |
@@ -1910,6 +2068,7 @@ drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc) | |||
1910 | 2068 | ||
1911 | if (state) { | 2069 | if (state) { |
1912 | state->mode_changed = false; | 2070 | state->mode_changed = false; |
2071 | state->active_changed = false; | ||
1913 | state->planes_changed = false; | 2072 | state->planes_changed = false; |
1914 | state->event = NULL; | 2073 | state->event = NULL; |
1915 | } | 2074 | } |
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index ad2934ba0bd2..b459888f6310 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -691,6 +691,10 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, | |||
691 | if (cursor) | 691 | if (cursor) |
692 | cursor->possible_crtcs = 1 << drm_crtc_index(crtc); | 692 | cursor->possible_crtcs = 1 << drm_crtc_index(crtc); |
693 | 693 | ||
694 | if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { | ||
695 | drm_object_attach_property(&crtc->base, config->prop_active, 0); | ||
696 | } | ||
697 | |||
694 | return 0; | 698 | return 0; |
695 | } | 699 | } |
696 | EXPORT_SYMBOL(drm_crtc_init_with_planes); | 700 | EXPORT_SYMBOL(drm_crtc_init_with_planes); |
@@ -1481,6 +1485,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) | |||
1481 | return -ENOMEM; | 1485 | return -ENOMEM; |
1482 | dev->mode_config.prop_crtc_id = prop; | 1486 | dev->mode_config.prop_crtc_id = prop; |
1483 | 1487 | ||
1488 | prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC, | ||
1489 | "ACTIVE"); | ||
1490 | if (!prop) | ||
1491 | return -ENOMEM; | ||
1492 | dev->mode_config.prop_active = prop; | ||
1493 | |||
1484 | return 0; | 1494 | return 0; |
1485 | } | 1495 | } |
1486 | 1496 | ||
@@ -3810,7 +3820,7 @@ static struct drm_property *property_create_range(struct drm_device *dev, | |||
3810 | } | 3820 | } |
3811 | 3821 | ||
3812 | /** | 3822 | /** |
3813 | * drm_property_create_range - create a new ranged property type | 3823 | * drm_property_create_range - create a new unsigned ranged property type |
3814 | * @dev: drm device | 3824 | * @dev: drm device |
3815 | * @flags: flags specifying the property type | 3825 | * @flags: flags specifying the property type |
3816 | * @name: name of the property | 3826 | * @name: name of the property |
@@ -3821,8 +3831,8 @@ static struct drm_property *property_create_range(struct drm_device *dev, | |||
3821 | * object with drm_object_attach_property. The returned property object must be | 3831 | * object with drm_object_attach_property. The returned property object must be |
3822 | * freed with drm_property_destroy. | 3832 | * freed with drm_property_destroy. |
3823 | * | 3833 | * |
3824 | * Userspace is allowed to set any integer value in the (min, max) range | 3834 | * Userspace is allowed to set any unsigned integer value in the (min, max) |
3825 | * inclusive. | 3835 | * range inclusive. |
3826 | * | 3836 | * |
3827 | * Returns: | 3837 | * Returns: |
3828 | * A pointer to the newly created property on success, NULL on failure. | 3838 | * A pointer to the newly created property on success, NULL on failure. |
@@ -3836,6 +3846,24 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags | |||
3836 | } | 3846 | } |
3837 | EXPORT_SYMBOL(drm_property_create_range); | 3847 | EXPORT_SYMBOL(drm_property_create_range); |
3838 | 3848 | ||
3849 | /** | ||
3850 | * drm_property_create_signed_range - create a new signed ranged property type | ||
3851 | * @dev: drm device | ||
3852 | * @flags: flags specifying the property type | ||
3853 | * @name: name of the property | ||
3854 | * @min: minimum value of the property | ||
3855 | * @max: maximum value of the property | ||
3856 | * | ||
3857 | * This creates a new generic drm property which can then be attached to a drm | ||
3858 | * object with drm_object_attach_property. The returned property object must be | ||
3859 | * freed with drm_property_destroy. | ||
3860 | * | ||
3861 | * Userspace is allowed to set any signed integer value in the (min, max) | ||
3862 | * range inclusive. | ||
3863 | * | ||
3864 | * Returns: | ||
3865 | * A pointer to the newly created property on success, NULL on failure. | ||
3866 | */ | ||
3839 | struct drm_property *drm_property_create_signed_range(struct drm_device *dev, | 3867 | struct drm_property *drm_property_create_signed_range(struct drm_device *dev, |
3840 | int flags, const char *name, | 3868 | int flags, const char *name, |
3841 | int64_t min, int64_t max) | 3869 | int64_t min, int64_t max) |
@@ -3845,6 +3873,23 @@ struct drm_property *drm_property_create_signed_range(struct drm_device *dev, | |||
3845 | } | 3873 | } |
3846 | EXPORT_SYMBOL(drm_property_create_signed_range); | 3874 | EXPORT_SYMBOL(drm_property_create_signed_range); |
3847 | 3875 | ||
3876 | /** | ||
3877 | * drm_property_create_object - create a new object property type | ||
3878 | * @dev: drm device | ||
3879 | * @flags: flags specifying the property type | ||
3880 | * @name: name of the property | ||
3881 | * @type: object type from DRM_MODE_OBJECT_* defines | ||
3882 | * | ||
3883 | * This creates a new generic drm property which can then be attached to a drm | ||
3884 | * object with drm_object_attach_property. The returned property object must be | ||
3885 | * freed with drm_property_destroy. | ||
3886 | * | ||
3887 | * Userspace is only allowed to set this to any property value of the given | ||
3888 | * @type. Only useful for atomic properties, which is enforced. | ||
3889 | * | ||
3890 | * Returns: | ||
3891 | * A pointer to the newly created property on success, NULL on failure. | ||
3892 | */ | ||
3848 | struct drm_property *drm_property_create_object(struct drm_device *dev, | 3893 | struct drm_property *drm_property_create_object(struct drm_device *dev, |
3849 | int flags, const char *name, uint32_t type) | 3894 | int flags, const char *name, uint32_t type) |
3850 | { | 3895 | { |
@@ -3852,6 +3897,9 @@ struct drm_property *drm_property_create_object(struct drm_device *dev, | |||
3852 | 3897 | ||
3853 | flags |= DRM_MODE_PROP_OBJECT; | 3898 | flags |= DRM_MODE_PROP_OBJECT; |
3854 | 3899 | ||
3900 | if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC))) | ||
3901 | return NULL; | ||
3902 | |||
3855 | property = drm_property_create(dev, flags, name, 1); | 3903 | property = drm_property_create(dev, flags, name, 1); |
3856 | if (!property) | 3904 | if (!property) |
3857 | return NULL; | 3905 | return NULL; |
@@ -3863,6 +3911,28 @@ struct drm_property *drm_property_create_object(struct drm_device *dev, | |||
3863 | EXPORT_SYMBOL(drm_property_create_object); | 3911 | EXPORT_SYMBOL(drm_property_create_object); |
3864 | 3912 | ||
3865 | /** | 3913 | /** |
3914 | * drm_property_create_bool - create a new boolean property type | ||
3915 | * @dev: drm device | ||
3916 | * @flags: flags specifying the property type | ||
3917 | * @name: name of the property | ||
3918 | * | ||
3919 | * This creates a new generic drm property which can then be attached to a drm | ||
3920 | * object with drm_object_attach_property. The returned property object must be | ||
3921 | * freed with drm_property_destroy. | ||
3922 | * | ||
3923 | * This is implemented as a ranged property with only {0, 1} as valid values. | ||
3924 | * | ||
3925 | * Returns: | ||
3926 | * A pointer to the newly created property on success, NULL on failure. | ||
3927 | */ | ||
3928 | struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, | ||
3929 | const char *name) | ||
3930 | { | ||
3931 | return drm_property_create_range(dev, flags, name, 0, 1); | ||
3932 | } | ||
3933 | EXPORT_SYMBOL(drm_property_create_bool); | ||
3934 | |||
3935 | /** | ||
3866 | * drm_property_add_enum - add a possible value to an enumeration property | 3936 | * drm_property_add_enum - add a possible value to an enumeration property |
3867 | * @property: enumeration property to change | 3937 | * @property: enumeration property to change |
3868 | * @index: index of the new enumeration | 3938 | * @index: index of the new enumeration |
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 4dcdcad9f16d..5ba5792bfdba 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c | |||
@@ -435,7 +435,8 @@ int drm_plane_helper_commit(struct drm_plane *plane, | |||
435 | goto out; | 435 | goto out; |
436 | } | 436 | } |
437 | 437 | ||
438 | if (plane_funcs->prepare_fb && plane_state->fb) { | 438 | if (plane_funcs->prepare_fb && plane_state->fb && |
439 | plane_state->fb != old_fb) { | ||
439 | ret = plane_funcs->prepare_fb(plane, plane_state->fb); | 440 | ret = plane_funcs->prepare_fb(plane, plane_state->fb); |
440 | if (ret) | 441 | if (ret) |
441 | goto out; | 442 | goto out; |
@@ -464,6 +465,13 @@ int drm_plane_helper_commit(struct drm_plane *plane, | |||
464 | crtc_funcs[i]->atomic_flush(crtc[i]); | 465 | crtc_funcs[i]->atomic_flush(crtc[i]); |
465 | } | 466 | } |
466 | 467 | ||
468 | /* | ||
469 | * If we only moved the plane and didn't change fb's, there's no need to | ||
470 | * wait for vblank. | ||
471 | */ | ||
472 | if (plane->state->fb == old_fb) | ||
473 | goto out; | ||
474 | |||
467 | for (i = 0; i < 2; i++) { | 475 | for (i = 0; i < 2; i++) { |
468 | if (!crtc[i]) | 476 | if (!crtc[i]) |
469 | continue; | 477 | continue; |
@@ -492,7 +500,7 @@ out: | |||
492 | } | 500 | } |
493 | 501 | ||
494 | /** | 502 | /** |
495 | * drm_plane_helper_update() - Helper for primary plane update | 503 | * drm_plane_helper_update() - Transitional helper for plane update |
496 | * @plane: plane object to update | 504 | * @plane: plane object to update |
497 | * @crtc: owning CRTC of owning plane | 505 | * @crtc: owning CRTC of owning plane |
498 | * @fb: framebuffer to flip onto plane | 506 | * @fb: framebuffer to flip onto plane |
@@ -549,7 +557,7 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, | |||
549 | EXPORT_SYMBOL(drm_plane_helper_update); | 557 | EXPORT_SYMBOL(drm_plane_helper_update); |
550 | 558 | ||
551 | /** | 559 | /** |
552 | * drm_plane_helper_disable() - Helper for primary plane disable | 560 | * drm_plane_helper_disable() - Transitional helper for plane disable |
553 | * @plane: plane to disable | 561 | * @plane: plane to disable |
554 | * | 562 | * |
555 | * Provides a default plane disable handler using the atomic plane update | 563 | * Provides a default plane disable handler using the atomic plane update |
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index a0ea4ded3cb5..8039d54a7441 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h | |||
@@ -82,6 +82,8 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc, | |||
82 | struct drm_framebuffer *fb, | 82 | struct drm_framebuffer *fb, |
83 | struct drm_pending_vblank_event *event, | 83 | struct drm_pending_vblank_event *event, |
84 | uint32_t flags); | 84 | uint32_t flags); |
85 | void drm_atomic_helper_connector_dpms(struct drm_connector *connector, | ||
86 | int mode); | ||
85 | 87 | ||
86 | /* default implementations for state handling */ | 88 | /* default implementations for state handling */ |
87 | void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc); | 89 | void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc); |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 0ebd9286b332..02614170c034 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -253,6 +253,7 @@ struct drm_atomic_state; | |||
253 | * @enable: whether the CRTC should be enabled, gates all other state | 253 | * @enable: whether the CRTC should be enabled, gates all other state |
254 | * @active: whether the CRTC is actively displaying (used for DPMS) | 254 | * @active: whether the CRTC is actively displaying (used for DPMS) |
255 | * @mode_changed: for use by helpers and drivers when computing state updates | 255 | * @mode_changed: for use by helpers and drivers when computing state updates |
256 | * @active_changed: for use by helpers and drivers when computing state updates | ||
256 | * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes | 257 | * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes |
257 | * @last_vblank_count: for helpers and drivers to capture the vblank of the | 258 | * @last_vblank_count: for helpers and drivers to capture the vblank of the |
258 | * update to ensure framebuffer cleanup isn't done too early | 259 | * update to ensure framebuffer cleanup isn't done too early |
@@ -278,6 +279,7 @@ struct drm_crtc_state { | |||
278 | /* computed state bits used by helpers and drivers */ | 279 | /* computed state bits used by helpers and drivers */ |
279 | bool planes_changed : 1; | 280 | bool planes_changed : 1; |
280 | bool mode_changed : 1; | 281 | bool mode_changed : 1; |
282 | bool active_changed : 1; | ||
281 | 283 | ||
282 | /* attached planes bitmask: | 284 | /* attached planes bitmask: |
283 | * WARNING: transitional helpers do not maintain plane_mask so | 285 | * WARNING: transitional helpers do not maintain plane_mask so |
@@ -910,6 +912,7 @@ struct drm_bridge { | |||
910 | * struct struct drm_atomic_state - the global state object for atomic updates | 912 | * struct struct drm_atomic_state - the global state object for atomic updates |
911 | * @dev: parent DRM device | 913 | * @dev: parent DRM device |
912 | * @allow_modeset: allow full modeset | 914 | * @allow_modeset: allow full modeset |
915 | * @legacy_cursor_update: hint to enforce legacy cursor ioctl semantics | ||
913 | * @planes: pointer to array of plane pointers | 916 | * @planes: pointer to array of plane pointers |
914 | * @plane_states: pointer to array of plane states pointers | 917 | * @plane_states: pointer to array of plane states pointers |
915 | * @crtcs: pointer to array of CRTC pointers | 918 | * @crtcs: pointer to array of CRTC pointers |
@@ -922,6 +925,7 @@ struct drm_bridge { | |||
922 | struct drm_atomic_state { | 925 | struct drm_atomic_state { |
923 | struct drm_device *dev; | 926 | struct drm_device *dev; |
924 | bool allow_modeset : 1; | 927 | bool allow_modeset : 1; |
928 | bool legacy_cursor_update : 1; | ||
925 | struct drm_plane **planes; | 929 | struct drm_plane **planes; |
926 | struct drm_plane_state **plane_states; | 930 | struct drm_plane_state **plane_states; |
927 | struct drm_crtc **crtcs; | 931 | struct drm_crtc **crtcs; |
@@ -1117,6 +1121,7 @@ struct drm_mode_config { | |||
1117 | struct drm_property *prop_crtc_h; | 1121 | struct drm_property *prop_crtc_h; |
1118 | struct drm_property *prop_fb_id; | 1122 | struct drm_property *prop_fb_id; |
1119 | struct drm_property *prop_crtc_id; | 1123 | struct drm_property *prop_crtc_id; |
1124 | struct drm_property *prop_active; | ||
1120 | 1125 | ||
1121 | /* DVI-I properties */ | 1126 | /* DVI-I properties */ |
1122 | struct drm_property *dvi_i_subconnector_property; | 1127 | struct drm_property *dvi_i_subconnector_property; |
@@ -1349,6 +1354,8 @@ struct drm_property *drm_property_create_signed_range(struct drm_device *dev, | |||
1349 | int64_t min, int64_t max); | 1354 | int64_t min, int64_t max); |
1350 | struct drm_property *drm_property_create_object(struct drm_device *dev, | 1355 | struct drm_property *drm_property_create_object(struct drm_device *dev, |
1351 | int flags, const char *name, uint32_t type); | 1356 | int flags, const char *name, uint32_t type); |
1357 | struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, | ||
1358 | const char *name); | ||
1352 | extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); | 1359 | extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); |
1353 | extern int drm_property_add_enum(struct drm_property *property, int index, | 1360 | extern int drm_property_add_enum(struct drm_property *property, int index, |
1354 | uint64_t value, const char *name); | 1361 | uint64_t value, const char *name); |
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 5810c027acdc..c250a22b39ab 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h | |||
@@ -58,11 +58,19 @@ enum mode_set_atomic { | |||
58 | * @mode_set_base_atomic: non-blocking mode set (used for kgdb support) | 58 | * @mode_set_base_atomic: non-blocking mode set (used for kgdb support) |
59 | * @load_lut: load color palette | 59 | * @load_lut: load color palette |
60 | * @disable: disable CRTC when no longer in use | 60 | * @disable: disable CRTC when no longer in use |
61 | * @enable: enable CRTC | ||
61 | * @atomic_check: check for validity of an atomic state | 62 | * @atomic_check: check for validity of an atomic state |
62 | * @atomic_begin: begin atomic update | 63 | * @atomic_begin: begin atomic update |
63 | * @atomic_flush: flush atomic update | 64 | * @atomic_flush: flush atomic update |
64 | * | 65 | * |
65 | * The helper operations are called by the mid-layer CRTC helper. | 66 | * The helper operations are called by the mid-layer CRTC helper. |
67 | * | ||
68 | * Note that with atomic helpers @dpms, @prepare and @commit hooks are | ||
69 | * deprecated. Used @enable and @disable instead exclusively. | ||
70 | * | ||
71 | * With legacy crtc helpers there's a big semantic difference between @disable | ||
72 | * and the other hooks: @disable also needs to release any resources acquired in | ||
73 | * @mode_set (like shared PLLs). | ||
66 | */ | 74 | */ |
67 | struct drm_crtc_helper_funcs { | 75 | struct drm_crtc_helper_funcs { |
68 | /* | 76 | /* |
@@ -93,8 +101,8 @@ struct drm_crtc_helper_funcs { | |||
93 | /* reload the current crtc LUT */ | 101 | /* reload the current crtc LUT */ |
94 | void (*load_lut)(struct drm_crtc *crtc); | 102 | void (*load_lut)(struct drm_crtc *crtc); |
95 | 103 | ||
96 | /* disable crtc when not in use - more explicit than dpms off */ | ||
97 | void (*disable)(struct drm_crtc *crtc); | 104 | void (*disable)(struct drm_crtc *crtc); |
105 | void (*enable)(struct drm_crtc *crtc); | ||
98 | 106 | ||
99 | /* atomic helpers */ | 107 | /* atomic helpers */ |
100 | int (*atomic_check)(struct drm_crtc *crtc, | 108 | int (*atomic_check)(struct drm_crtc *crtc, |
@@ -115,9 +123,17 @@ struct drm_crtc_helper_funcs { | |||
115 | * @get_crtc: return CRTC that the encoder is currently attached to | 123 | * @get_crtc: return CRTC that the encoder is currently attached to |
116 | * @detect: connection status detection | 124 | * @detect: connection status detection |
117 | * @disable: disable encoder when not in use (overrides DPMS off) | 125 | * @disable: disable encoder when not in use (overrides DPMS off) |
126 | * @enable: enable encoder | ||
118 | * @atomic_check: check for validity of an atomic update | 127 | * @atomic_check: check for validity of an atomic update |
119 | * | 128 | * |
120 | * The helper operations are called by the mid-layer CRTC helper. | 129 | * The helper operations are called by the mid-layer CRTC helper. |
130 | * | ||
131 | * Note that with atomic helpers @dpms, @prepare and @commit hooks are | ||
132 | * deprecated. Used @enable and @disable instead exclusively. | ||
133 | * | ||
134 | * With legacy crtc helpers there's a big semantic difference between @disable | ||
135 | * and the other hooks: @disable also needs to release any resources acquired in | ||
136 | * @mode_set (like shared PLLs). | ||
121 | */ | 137 | */ |
122 | struct drm_encoder_helper_funcs { | 138 | struct drm_encoder_helper_funcs { |
123 | void (*dpms)(struct drm_encoder *encoder, int mode); | 139 | void (*dpms)(struct drm_encoder *encoder, int mode); |
@@ -136,9 +152,10 @@ struct drm_encoder_helper_funcs { | |||
136 | /* detect for DAC style encoders */ | 152 | /* detect for DAC style encoders */ |
137 | enum drm_connector_status (*detect)(struct drm_encoder *encoder, | 153 | enum drm_connector_status (*detect)(struct drm_encoder *encoder, |
138 | struct drm_connector *connector); | 154 | struct drm_connector *connector); |
139 | /* disable encoder when not in use - more explicit than dpms off */ | ||
140 | void (*disable)(struct drm_encoder *encoder); | 155 | void (*disable)(struct drm_encoder *encoder); |
141 | 156 | ||
157 | void (*enable)(struct drm_encoder *encoder); | ||
158 | |||
142 | /* atomic helpers */ | 159 | /* atomic helpers */ |
143 | int (*atomic_check)(struct drm_encoder *encoder, | 160 | int (*atomic_check)(struct drm_encoder *encoder, |
144 | struct drm_crtc_state *crtc_state, | 161 | struct drm_crtc_state *crtc_state, |