diff options
author | Dave Airlie <airlied@redhat.com> | 2010-01-28 02:15:25 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-01-31 19:13:15 -0500 |
commit | f28cf33945cc112f8ee835512b7440905dc29ad2 (patch) | |
tree | dc824913b484b5f726f23692ff0e7e100f7a3e7a | |
parent | 43c33ed87d0f1b900a6a3014db556ecc7f4a989b (diff) |
drm/kms/radeon: pick digitial encoders smarter. (v3)
booting a Lenovo W500 with LVDS + DP outputs showed up a TODO we had
on our list, to pick a correct digital encoder block. The LVTMA
encoder requires the second digital encoder, all others can use any
encoder at all.
This fixes the digital encoder selection logic to enable LVDS/DP combos
to work okay.
V2: fix silly addition of connector dig_block and cleanup the other
places in the code that pick the encoder.
V3: rename to dig_encoder and clean up further - also fix
the picking algorithm.
tested on Lenovo W500 + desktop 3650 cards.
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/radeon/atombios_dp.c | 23 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_encoders.c | 163 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 2 |
3 files changed, 99 insertions, 89 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 9c023d25aad0..71060114d5de 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c | |||
@@ -596,21 +596,14 @@ void dp_link_train(struct drm_encoder *encoder, | |||
596 | return; | 596 | return; |
597 | dig_connector = radeon_connector->con_priv; | 597 | dig_connector = radeon_connector->con_priv; |
598 | 598 | ||
599 | if (ASIC_IS_DCE32(rdev)) { | 599 | if (dig->dig_encoder) |
600 | if (dig->dig_block) | 600 | enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER; |
601 | enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER; | 601 | else |
602 | else | 602 | enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER; |
603 | enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER; | 603 | if (dig_connector->linkb) |
604 | if (dig_connector->linkb) | 604 | enc_id |= ATOM_DP_CONFIG_LINK_B; |
605 | enc_id |= ATOM_DP_CONFIG_LINK_B; | 605 | else |
606 | else | 606 | enc_id |= ATOM_DP_CONFIG_LINK_A; |
607 | enc_id |= ATOM_DP_CONFIG_LINK_A; | ||
608 | } else { | ||
609 | if (dig_connector->linkb) | ||
610 | enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER | ATOM_DP_CONFIG_LINK_B; | ||
611 | else | ||
612 | enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER | ATOM_DP_CONFIG_LINK_A; | ||
613 | } | ||
614 | 607 | ||
615 | memset(link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); | 608 | memset(link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); |
616 | if (dig_connector->dp_clock == 270000) | 609 | if (dig_connector->dp_clock == 270000) |
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 10746c9c8051..3c91724457ca 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c | |||
@@ -156,6 +156,26 @@ radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t | |||
156 | return ret; | 156 | return ret; |
157 | } | 157 | } |
158 | 158 | ||
159 | static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder) | ||
160 | { | ||
161 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
162 | switch (radeon_encoder->encoder_id) { | ||
163 | case ENCODER_OBJECT_ID_INTERNAL_LVDS: | ||
164 | case ENCODER_OBJECT_ID_INTERNAL_TMDS1: | ||
165 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: | ||
166 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: | ||
167 | case ENCODER_OBJECT_ID_INTERNAL_DVO1: | ||
168 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: | ||
169 | case ENCODER_OBJECT_ID_INTERNAL_DDI: | ||
170 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: | ||
171 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: | ||
172 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: | ||
173 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: | ||
174 | return true; | ||
175 | default: | ||
176 | return false; | ||
177 | } | ||
178 | } | ||
159 | void | 179 | void |
160 | radeon_link_encoder_connector(struct drm_device *dev) | 180 | radeon_link_encoder_connector(struct drm_device *dev) |
161 | { | 181 | { |
@@ -676,31 +696,11 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) | |||
676 | 696 | ||
677 | memset(&args, 0, sizeof(args)); | 697 | memset(&args, 0, sizeof(args)); |
678 | 698 | ||
679 | if (ASIC_IS_DCE32(rdev)) { | 699 | if (dig->dig_encoder) |
680 | if (dig->dig_block) | 700 | index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); |
681 | index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); | 701 | else |
682 | else | 702 | index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); |
683 | index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); | 703 | num = dig->dig_encoder + 1; |
684 | num = dig->dig_block + 1; | ||
685 | } else { | ||
686 | switch (radeon_encoder->encoder_id) { | ||
687 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: | ||
688 | /* XXX doesn't really matter which dig encoder we pick as long as it's | ||
689 | * not already in use | ||
690 | */ | ||
691 | if (dig_connector->linkb) | ||
692 | index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); | ||
693 | else | ||
694 | index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); | ||
695 | num = 1; | ||
696 | break; | ||
697 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: | ||
698 | /* Only dig2 encoder can drive LVTMA */ | ||
699 | index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); | ||
700 | num = 2; | ||
701 | break; | ||
702 | } | ||
703 | } | ||
704 | 704 | ||
705 | atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); | 705 | atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); |
706 | 706 | ||
@@ -822,7 +822,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t | |||
822 | args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); | 822 | args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); |
823 | } | 823 | } |
824 | if (ASIC_IS_DCE32(rdev)) { | 824 | if (ASIC_IS_DCE32(rdev)) { |
825 | if (dig->dig_block) | 825 | if (dig->dig_encoder == 1) |
826 | args.v2.acConfig.ucEncoderSel = 1; | 826 | args.v2.acConfig.ucEncoderSel = 1; |
827 | if (dig_connector->linkb) | 827 | if (dig_connector->linkb) |
828 | args.v2.acConfig.ucLinkSel = 1; | 828 | args.v2.acConfig.ucLinkSel = 1; |
@@ -849,17 +849,16 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t | |||
849 | args.v2.acConfig.fCoherentMode = 1; | 849 | args.v2.acConfig.fCoherentMode = 1; |
850 | } | 850 | } |
851 | } else { | 851 | } else { |
852 | |||
852 | args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; | 853 | args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; |
853 | 854 | ||
855 | if (dig->dig_encoder) | ||
856 | args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; | ||
857 | else | ||
858 | args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; | ||
859 | |||
854 | switch (radeon_encoder->encoder_id) { | 860 | switch (radeon_encoder->encoder_id) { |
855 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: | 861 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
856 | /* XXX doesn't really matter which dig encoder we pick as long as it's | ||
857 | * not already in use | ||
858 | */ | ||
859 | if (dig_connector->linkb) | ||
860 | args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; | ||
861 | else | ||
862 | args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; | ||
863 | if (rdev->flags & RADEON_IS_IGP) { | 862 | if (rdev->flags & RADEON_IS_IGP) { |
864 | if (radeon_encoder->pixel_clock > 165000) { | 863 | if (radeon_encoder->pixel_clock > 165000) { |
865 | if (dig_connector->igp_lane_info & 0x3) | 864 | if (dig_connector->igp_lane_info & 0x3) |
@@ -878,10 +877,6 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t | |||
878 | } | 877 | } |
879 | } | 878 | } |
880 | break; | 879 | break; |
881 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: | ||
882 | /* Only dig2 encoder can drive LVTMA */ | ||
883 | args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; | ||
884 | break; | ||
885 | } | 880 | } |
886 | 881 | ||
887 | if (radeon_encoder->pixel_clock > 165000) | 882 | if (radeon_encoder->pixel_clock > 165000) |
@@ -1046,6 +1041,7 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder) | |||
1046 | union crtc_sourc_param args; | 1041 | union crtc_sourc_param args; |
1047 | int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); | 1042 | int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); |
1048 | uint8_t frev, crev; | 1043 | uint8_t frev, crev; |
1044 | struct radeon_encoder_atom_dig *dig; | ||
1049 | 1045 | ||
1050 | memset(&args, 0, sizeof(args)); | 1046 | memset(&args, 0, sizeof(args)); |
1051 | 1047 | ||
@@ -1109,40 +1105,16 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder) | |||
1109 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: | 1105 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: |
1110 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: | 1106 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: |
1111 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: | 1107 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: |
1112 | if (ASIC_IS_DCE32(rdev)) { | 1108 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: |
1113 | if (radeon_crtc->crtc_id) | 1109 | dig = radeon_encoder->enc_priv; |
1114 | args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; | 1110 | if (dig->dig_encoder) |
1115 | else | 1111 | args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; |
1116 | args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; | 1112 | else |
1117 | } else { | 1113 | args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; |
1118 | struct drm_connector *connector; | ||
1119 | struct radeon_connector *radeon_connector; | ||
1120 | struct radeon_connector_atom_dig *dig_connector; | ||
1121 | |||
1122 | connector = radeon_get_connector_for_encoder(encoder); | ||
1123 | if (!connector) | ||
1124 | return; | ||
1125 | radeon_connector = to_radeon_connector(connector); | ||
1126 | if (!radeon_connector->con_priv) | ||
1127 | return; | ||
1128 | dig_connector = radeon_connector->con_priv; | ||
1129 | |||
1130 | /* XXX doesn't really matter which dig encoder we pick as long as it's | ||
1131 | * not already in use | ||
1132 | */ | ||
1133 | if (dig_connector->linkb) | ||
1134 | args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; | ||
1135 | else | ||
1136 | args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; | ||
1137 | } | ||
1138 | break; | 1114 | break; |
1139 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: | 1115 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: |
1140 | args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID; | 1116 | args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID; |
1141 | break; | 1117 | break; |
1142 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: | ||
1143 | /* Only dig2 encoder can drive LVTMA */ | ||
1144 | args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; | ||
1145 | break; | ||
1146 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: | 1118 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: |
1147 | if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) | 1119 | if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) |
1148 | args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; | 1120 | args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; |
@@ -1202,6 +1174,47 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder, | |||
1202 | } | 1174 | } |
1203 | } | 1175 | } |
1204 | 1176 | ||
1177 | static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) | ||
1178 | { | ||
1179 | struct drm_device *dev = encoder->dev; | ||
1180 | struct radeon_device *rdev = dev->dev_private; | ||
1181 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); | ||
1182 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
1183 | struct drm_encoder *test_encoder; | ||
1184 | struct radeon_encoder_atom_dig *dig; | ||
1185 | uint32_t dig_enc_in_use = 0; | ||
1186 | /* on DCE32 and encoder can driver any block so just crtc id */ | ||
1187 | if (ASIC_IS_DCE32(rdev)) { | ||
1188 | return radeon_crtc->crtc_id; | ||
1189 | } | ||
1190 | |||
1191 | /* on DCE3 - LVTMA can only be driven by DIGB */ | ||
1192 | list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { | ||
1193 | struct radeon_encoder *radeon_test_encoder; | ||
1194 | |||
1195 | if (encoder == test_encoder) | ||
1196 | continue; | ||
1197 | |||
1198 | if (!radeon_encoder_is_digital(test_encoder)) | ||
1199 | continue; | ||
1200 | |||
1201 | radeon_test_encoder = to_radeon_encoder(test_encoder); | ||
1202 | dig = radeon_test_encoder->enc_priv; | ||
1203 | |||
1204 | if (dig->dig_encoder >= 0) | ||
1205 | dig_enc_in_use |= (1 << dig->dig_encoder); | ||
1206 | } | ||
1207 | |||
1208 | if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA) { | ||
1209 | if (dig_enc_in_use & 0x2) | ||
1210 | DRM_ERROR("LVDS required digital encoder 2 but it was in use - stealing\n"); | ||
1211 | return 1; | ||
1212 | } | ||
1213 | if (!(dig_enc_in_use & 1)) | ||
1214 | return 0; | ||
1215 | return 1; | ||
1216 | } | ||
1217 | |||
1205 | static void | 1218 | static void |
1206 | radeon_atom_encoder_mode_set(struct drm_encoder *encoder, | 1219 | radeon_atom_encoder_mode_set(struct drm_encoder *encoder, |
1207 | struct drm_display_mode *mode, | 1220 | struct drm_display_mode *mode, |
@@ -1214,12 +1227,9 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, | |||
1214 | 1227 | ||
1215 | if (radeon_encoder->active_device & | 1228 | if (radeon_encoder->active_device & |
1216 | (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) { | 1229 | (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) { |
1217 | if (radeon_encoder->enc_priv) { | 1230 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; |
1218 | struct radeon_encoder_atom_dig *dig; | 1231 | if (dig) |
1219 | 1232 | dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder); | |
1220 | dig = radeon_encoder->enc_priv; | ||
1221 | dig->dig_block = radeon_crtc->crtc_id; | ||
1222 | } | ||
1223 | } | 1233 | } |
1224 | radeon_encoder->pixel_clock = adjusted_mode->clock; | 1234 | radeon_encoder->pixel_clock = adjusted_mode->clock; |
1225 | 1235 | ||
@@ -1379,7 +1389,13 @@ static void radeon_atom_encoder_commit(struct drm_encoder *encoder) | |||
1379 | static void radeon_atom_encoder_disable(struct drm_encoder *encoder) | 1389 | static void radeon_atom_encoder_disable(struct drm_encoder *encoder) |
1380 | { | 1390 | { |
1381 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | 1391 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
1392 | struct radeon_encoder_atom_dig *dig; | ||
1382 | radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); | 1393 | radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); |
1394 | |||
1395 | if (radeon_encoder_is_digital(encoder)) { | ||
1396 | dig = radeon_encoder->enc_priv; | ||
1397 | dig->dig_encoder = -1; | ||
1398 | } | ||
1383 | radeon_encoder->active_device = 0; | 1399 | radeon_encoder->active_device = 0; |
1384 | } | 1400 | } |
1385 | 1401 | ||
@@ -1436,6 +1452,7 @@ radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) | |||
1436 | 1452 | ||
1437 | /* coherent mode by default */ | 1453 | /* coherent mode by default */ |
1438 | dig->coherent_mode = true; | 1454 | dig->coherent_mode = true; |
1455 | dig->dig_encoder = -1; | ||
1439 | 1456 | ||
1440 | return dig; | 1457 | return dig; |
1441 | } | 1458 | } |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 96b851f92f4c..e81b2aeb6a8f 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
@@ -299,7 +299,7 @@ struct radeon_atom_ss { | |||
299 | struct radeon_encoder_atom_dig { | 299 | struct radeon_encoder_atom_dig { |
300 | /* atom dig */ | 300 | /* atom dig */ |
301 | bool coherent_mode; | 301 | bool coherent_mode; |
302 | int dig_block; | 302 | int dig_encoder; /* -1 disabled, 0 DIGA, 1 DIGB */ |
303 | /* atom lvds */ | 303 | /* atom lvds */ |
304 | uint32_t lvds_misc; | 304 | uint32_t lvds_misc; |
305 | uint16_t panel_pwr_delay; | 305 | uint16_t panel_pwr_delay; |