diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/dispnv50/disp.c')
| -rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/disp.c | 103 |
1 files changed, 74 insertions, 29 deletions
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 26af45785939..67107f0b1299 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c | |||
| @@ -561,7 +561,7 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) | |||
| 561 | u32 max_ac_packet; | 561 | u32 max_ac_packet; |
| 562 | union hdmi_infoframe avi_frame; | 562 | union hdmi_infoframe avi_frame; |
| 563 | union hdmi_infoframe vendor_frame; | 563 | union hdmi_infoframe vendor_frame; |
| 564 | bool scdc_supported, high_tmds_clock_ratio = false, scrambling = false; | 564 | bool high_tmds_clock_ratio = false, scrambling = false; |
| 565 | u8 config; | 565 | u8 config; |
| 566 | int ret; | 566 | int ret; |
| 567 | int size; | 567 | int size; |
| @@ -571,10 +571,9 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) | |||
| 571 | return; | 571 | return; |
| 572 | 572 | ||
| 573 | hdmi = &nv_connector->base.display_info.hdmi; | 573 | hdmi = &nv_connector->base.display_info.hdmi; |
| 574 | scdc_supported = hdmi->scdc.supported; | ||
| 575 | 574 | ||
| 576 | ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, mode, | 575 | ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, |
| 577 | scdc_supported); | 576 | &nv_connector->base, mode); |
| 578 | if (!ret) { | 577 | if (!ret) { |
| 579 | /* We have an AVI InfoFrame, populate it to the display */ | 578 | /* We have an AVI InfoFrame, populate it to the display */ |
| 580 | args.pwr.avi_infoframe_length | 579 | args.pwr.avi_infoframe_length |
| @@ -680,6 +679,8 @@ nv50_msto_payload(struct nv50_msto *msto) | |||
| 680 | struct nv50_mstm *mstm = mstc->mstm; | 679 | struct nv50_mstm *mstm = mstc->mstm; |
| 681 | int vcpi = mstc->port->vcpi.vcpi, i; | 680 | int vcpi = mstc->port->vcpi.vcpi, i; |
| 682 | 681 | ||
| 682 | WARN_ON(!mutex_is_locked(&mstm->mgr.payload_lock)); | ||
| 683 | |||
| 683 | NV_ATOMIC(drm, "%s: vcpi %d\n", msto->encoder.name, vcpi); | 684 | NV_ATOMIC(drm, "%s: vcpi %d\n", msto->encoder.name, vcpi); |
| 684 | for (i = 0; i < mstm->mgr.max_payloads; i++) { | 685 | for (i = 0; i < mstm->mgr.max_payloads; i++) { |
| 685 | struct drm_dp_payload *payload = &mstm->mgr.payloads[i]; | 686 | struct drm_dp_payload *payload = &mstm->mgr.payloads[i]; |
| @@ -704,14 +705,16 @@ nv50_msto_cleanup(struct nv50_msto *msto) | |||
| 704 | struct nv50_mstc *mstc = msto->mstc; | 705 | struct nv50_mstc *mstc = msto->mstc; |
| 705 | struct nv50_mstm *mstm = mstc->mstm; | 706 | struct nv50_mstm *mstm = mstc->mstm; |
| 706 | 707 | ||
| 708 | if (!msto->disabled) | ||
| 709 | return; | ||
| 710 | |||
| 707 | NV_ATOMIC(drm, "%s: msto cleanup\n", msto->encoder.name); | 711 | NV_ATOMIC(drm, "%s: msto cleanup\n", msto->encoder.name); |
| 708 | if (mstc->port && mstc->port->vcpi.vcpi > 0 && !nv50_msto_payload(msto)) | 712 | |
| 709 | drm_dp_mst_deallocate_vcpi(&mstm->mgr, mstc->port); | 713 | drm_dp_mst_deallocate_vcpi(&mstm->mgr, mstc->port); |
| 710 | if (msto->disabled) { | 714 | |
| 711 | msto->mstc = NULL; | 715 | msto->mstc = NULL; |
| 712 | msto->head = NULL; | 716 | msto->head = NULL; |
| 713 | msto->disabled = false; | 717 | msto->disabled = false; |
| 714 | } | ||
| 715 | } | 718 | } |
| 716 | 719 | ||
| 717 | static void | 720 | static void |
| @@ -731,8 +734,10 @@ nv50_msto_prepare(struct nv50_msto *msto) | |||
| 731 | (0x0100 << msto->head->base.index), | 734 | (0x0100 << msto->head->base.index), |
| 732 | }; | 735 | }; |
| 733 | 736 | ||
| 737 | mutex_lock(&mstm->mgr.payload_lock); | ||
| 738 | |||
| 734 | NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name); | 739 | NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name); |
| 735 | if (mstc->port && mstc->port->vcpi.vcpi > 0) { | 740 | if (mstc->port->vcpi.vcpi > 0) { |
| 736 | struct drm_dp_payload *payload = nv50_msto_payload(msto); | 741 | struct drm_dp_payload *payload = nv50_msto_payload(msto); |
| 737 | if (payload) { | 742 | if (payload) { |
| 738 | args.vcpi.start_slot = payload->start_slot; | 743 | args.vcpi.start_slot = payload->start_slot; |
| @@ -746,7 +751,9 @@ nv50_msto_prepare(struct nv50_msto *msto) | |||
| 746 | msto->encoder.name, msto->head->base.base.name, | 751 | msto->encoder.name, msto->head->base.base.name, |
| 747 | args.vcpi.start_slot, args.vcpi.num_slots, | 752 | args.vcpi.start_slot, args.vcpi.num_slots, |
| 748 | args.vcpi.pbn, args.vcpi.aligned_pbn); | 753 | args.vcpi.pbn, args.vcpi.aligned_pbn); |
| 754 | |||
| 749 | nvif_mthd(&drm->display->disp.object, 0, &args, sizeof(args)); | 755 | nvif_mthd(&drm->display->disp.object, 0, &args, sizeof(args)); |
| 756 | mutex_unlock(&mstm->mgr.payload_lock); | ||
| 750 | } | 757 | } |
| 751 | 758 | ||
| 752 | static int | 759 | static int |
| @@ -754,16 +761,23 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, | |||
| 754 | struct drm_crtc_state *crtc_state, | 761 | struct drm_crtc_state *crtc_state, |
| 755 | struct drm_connector_state *conn_state) | 762 | struct drm_connector_state *conn_state) |
| 756 | { | 763 | { |
| 757 | struct nv50_mstc *mstc = nv50_mstc(conn_state->connector); | 764 | struct drm_atomic_state *state = crtc_state->state; |
| 765 | struct drm_connector *connector = conn_state->connector; | ||
| 766 | struct nv50_mstc *mstc = nv50_mstc(connector); | ||
| 758 | struct nv50_mstm *mstm = mstc->mstm; | 767 | struct nv50_mstm *mstm = mstc->mstm; |
| 759 | int bpp = conn_state->connector->display_info.bpc * 3; | 768 | int bpp = connector->display_info.bpc * 3; |
| 760 | int slots; | 769 | int slots; |
| 761 | 770 | ||
| 762 | mstc->pbn = drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock, bpp); | 771 | mstc->pbn = drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock, |
| 772 | bpp); | ||
| 763 | 773 | ||
| 764 | slots = drm_dp_find_vcpi_slots(&mstm->mgr, mstc->pbn); | 774 | if (drm_atomic_crtc_needs_modeset(crtc_state) && |
| 765 | if (slots < 0) | 775 | !drm_connector_is_unregistered(connector)) { |
| 766 | return slots; | 776 | slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, |
| 777 | mstc->port, mstc->pbn); | ||
| 778 | if (slots < 0) | ||
| 779 | return slots; | ||
| 780 | } | ||
| 767 | 781 | ||
| 768 | return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, | 782 | return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, |
| 769 | mstc->native); | 783 | mstc->native); |
| @@ -829,8 +843,7 @@ nv50_msto_disable(struct drm_encoder *encoder) | |||
| 829 | struct nv50_mstc *mstc = msto->mstc; | 843 | struct nv50_mstc *mstc = msto->mstc; |
| 830 | struct nv50_mstm *mstm = mstc->mstm; | 844 | struct nv50_mstm *mstm = mstc->mstm; |
| 831 | 845 | ||
| 832 | if (mstc->port) | 846 | drm_dp_mst_reset_vcpi_slots(&mstm->mgr, mstc->port); |
| 833 | drm_dp_mst_reset_vcpi_slots(&mstm->mgr, mstc->port); | ||
| 834 | 847 | ||
| 835 | mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0); | 848 | mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0); |
| 836 | mstm->modified = true; | 849 | mstm->modified = true; |
| @@ -927,12 +940,43 @@ nv50_mstc_get_modes(struct drm_connector *connector) | |||
| 927 | return ret; | 940 | return ret; |
| 928 | } | 941 | } |
| 929 | 942 | ||
| 943 | static int | ||
| 944 | nv50_mstc_atomic_check(struct drm_connector *connector, | ||
| 945 | struct drm_connector_state *new_conn_state) | ||
| 946 | { | ||
| 947 | struct drm_atomic_state *state = new_conn_state->state; | ||
| 948 | struct nv50_mstc *mstc = nv50_mstc(connector); | ||
| 949 | struct drm_dp_mst_topology_mgr *mgr = &mstc->mstm->mgr; | ||
| 950 | struct drm_connector_state *old_conn_state = | ||
| 951 | drm_atomic_get_old_connector_state(state, connector); | ||
| 952 | struct drm_crtc_state *crtc_state; | ||
| 953 | struct drm_crtc *new_crtc = new_conn_state->crtc; | ||
| 954 | |||
| 955 | if (!old_conn_state->crtc) | ||
| 956 | return 0; | ||
| 957 | |||
| 958 | /* We only want to free VCPI if this state disables the CRTC on this | ||
| 959 | * connector | ||
| 960 | */ | ||
| 961 | if (new_crtc) { | ||
| 962 | crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); | ||
| 963 | |||
| 964 | if (!crtc_state || | ||
| 965 | !drm_atomic_crtc_needs_modeset(crtc_state) || | ||
| 966 | crtc_state->enable) | ||
| 967 | return 0; | ||
| 968 | } | ||
| 969 | |||
| 970 | return drm_dp_atomic_release_vcpi_slots(state, mgr, mstc->port); | ||
| 971 | } | ||
| 972 | |||
| 930 | static const struct drm_connector_helper_funcs | 973 | static const struct drm_connector_helper_funcs |
| 931 | nv50_mstc_help = { | 974 | nv50_mstc_help = { |
| 932 | .get_modes = nv50_mstc_get_modes, | 975 | .get_modes = nv50_mstc_get_modes, |
| 933 | .mode_valid = nv50_mstc_mode_valid, | 976 | .mode_valid = nv50_mstc_mode_valid, |
| 934 | .best_encoder = nv50_mstc_best_encoder, | 977 | .best_encoder = nv50_mstc_best_encoder, |
| 935 | .atomic_best_encoder = nv50_mstc_atomic_best_encoder, | 978 | .atomic_best_encoder = nv50_mstc_atomic_best_encoder, |
| 979 | .atomic_check = nv50_mstc_atomic_check, | ||
| 936 | }; | 980 | }; |
| 937 | 981 | ||
| 938 | static enum drm_connector_status | 982 | static enum drm_connector_status |
| @@ -942,7 +986,7 @@ nv50_mstc_detect(struct drm_connector *connector, bool force) | |||
| 942 | enum drm_connector_status conn_status; | 986 | enum drm_connector_status conn_status; |
| 943 | int ret; | 987 | int ret; |
| 944 | 988 | ||
| 945 | if (!mstc->port) | 989 | if (drm_connector_is_unregistered(connector)) |
| 946 | return connector_status_disconnected; | 990 | return connector_status_disconnected; |
| 947 | 991 | ||
| 948 | ret = pm_runtime_get_sync(connector->dev->dev); | 992 | ret = pm_runtime_get_sync(connector->dev->dev); |
| @@ -961,7 +1005,10 @@ static void | |||
| 961 | nv50_mstc_destroy(struct drm_connector *connector) | 1005 | nv50_mstc_destroy(struct drm_connector *connector) |
| 962 | { | 1006 | { |
| 963 | struct nv50_mstc *mstc = nv50_mstc(connector); | 1007 | struct nv50_mstc *mstc = nv50_mstc(connector); |
| 1008 | |||
| 964 | drm_connector_cleanup(&mstc->connector); | 1009 | drm_connector_cleanup(&mstc->connector); |
| 1010 | drm_dp_mst_put_port_malloc(mstc->port); | ||
| 1011 | |||
| 965 | kfree(mstc); | 1012 | kfree(mstc); |
| 966 | } | 1013 | } |
| 967 | 1014 | ||
| @@ -1009,6 +1056,7 @@ nv50_mstc_new(struct nv50_mstm *mstm, struct drm_dp_mst_port *port, | |||
| 1009 | drm_object_attach_property(&mstc->connector.base, dev->mode_config.path_property, 0); | 1056 | drm_object_attach_property(&mstc->connector.base, dev->mode_config.path_property, 0); |
| 1010 | drm_object_attach_property(&mstc->connector.base, dev->mode_config.tile_property, 0); | 1057 | drm_object_attach_property(&mstc->connector.base, dev->mode_config.tile_property, 0); |
| 1011 | drm_connector_set_path_property(&mstc->connector, path); | 1058 | drm_connector_set_path_property(&mstc->connector, path); |
| 1059 | drm_dp_mst_get_port_malloc(port); | ||
| 1012 | return 0; | 1060 | return 0; |
| 1013 | } | 1061 | } |
| 1014 | 1062 | ||
| @@ -1073,10 +1121,6 @@ nv50_mstm_destroy_connector(struct drm_dp_mst_topology_mgr *mgr, | |||
| 1073 | 1121 | ||
| 1074 | drm_fb_helper_remove_one_connector(&drm->fbcon->helper, &mstc->connector); | 1122 | drm_fb_helper_remove_one_connector(&drm->fbcon->helper, &mstc->connector); |
| 1075 | 1123 | ||
| 1076 | drm_modeset_lock(&drm->dev->mode_config.connection_mutex, NULL); | ||
| 1077 | mstc->port = NULL; | ||
| 1078 | drm_modeset_unlock(&drm->dev->mode_config.connection_mutex); | ||
| 1079 | |||
| 1080 | drm_connector_put(&mstc->connector); | 1124 | drm_connector_put(&mstc->connector); |
| 1081 | } | 1125 | } |
| 1082 | 1126 | ||
| @@ -1099,11 +1143,8 @@ nv50_mstm_add_connector(struct drm_dp_mst_topology_mgr *mgr, | |||
| 1099 | int ret; | 1143 | int ret; |
| 1100 | 1144 | ||
| 1101 | ret = nv50_mstc_new(mstm, port, path, &mstc); | 1145 | ret = nv50_mstc_new(mstm, port, path, &mstc); |
| 1102 | if (ret) { | 1146 | if (ret) |
| 1103 | if (mstc) | ||
| 1104 | mstc->connector.funcs->destroy(&mstc->connector); | ||
| 1105 | return NULL; | 1147 | return NULL; |
| 1106 | } | ||
| 1107 | 1148 | ||
| 1108 | return &mstc->connector; | 1149 | return &mstc->connector; |
| 1109 | } | 1150 | } |
| @@ -2117,6 +2158,10 @@ nv50_disp_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) | |||
| 2117 | return ret; | 2158 | return ret; |
| 2118 | } | 2159 | } |
| 2119 | 2160 | ||
| 2161 | ret = drm_dp_mst_atomic_check(state); | ||
| 2162 | if (ret) | ||
| 2163 | return ret; | ||
| 2164 | |||
| 2120 | return 0; | 2165 | return 0; |
| 2121 | } | 2166 | } |
| 2122 | 2167 | ||
