diff options
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_encoders.c | 183 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 1 |
2 files changed, 184 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 07df990a897b..041943df966b 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c | |||
| @@ -229,6 +229,27 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder) | |||
| 229 | return NULL; | 229 | return NULL; |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder) | ||
| 233 | { | ||
| 234 | struct drm_device *dev = encoder->dev; | ||
| 235 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
| 236 | struct drm_encoder *other_encoder; | ||
| 237 | struct radeon_encoder *other_radeon_encoder; | ||
| 238 | |||
| 239 | if (radeon_encoder->is_ext_encoder) | ||
| 240 | return NULL; | ||
| 241 | |||
| 242 | list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) { | ||
| 243 | if (other_encoder == encoder) | ||
| 244 | continue; | ||
| 245 | other_radeon_encoder = to_radeon_encoder(other_encoder); | ||
| 246 | if (other_radeon_encoder->is_ext_encoder && | ||
| 247 | (radeon_encoder->devices & other_radeon_encoder->devices)) | ||
| 248 | return other_encoder; | ||
| 249 | } | ||
| 250 | return NULL; | ||
| 251 | } | ||
| 252 | |||
| 232 | void radeon_panel_mode_fixup(struct drm_encoder *encoder, | 253 | void radeon_panel_mode_fixup(struct drm_encoder *encoder, |
| 233 | struct drm_display_mode *adjusted_mode) | 254 | struct drm_display_mode *adjusted_mode) |
| 234 | { | 255 | { |
| @@ -1021,6 +1042,75 @@ atombios_set_edp_panel_power(struct drm_connector *connector, int action) | |||
| 1021 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); | 1042 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); |
| 1022 | } | 1043 | } |
| 1023 | 1044 | ||
| 1045 | union external_encoder_control { | ||
| 1046 | EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1; | ||
| 1047 | }; | ||
| 1048 | |||
| 1049 | static void | ||
| 1050 | atombios_external_encoder_setup(struct drm_encoder *encoder, | ||
| 1051 | struct drm_encoder *ext_encoder, | ||
| 1052 | int action) | ||
| 1053 | { | ||
| 1054 | struct drm_device *dev = encoder->dev; | ||
| 1055 | struct radeon_device *rdev = dev->dev_private; | ||
| 1056 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
| 1057 | union external_encoder_control args; | ||
| 1058 | struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); | ||
| 1059 | int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl); | ||
| 1060 | u8 frev, crev; | ||
| 1061 | int dp_clock = 0; | ||
| 1062 | int dp_lane_count = 0; | ||
| 1063 | int connector_object_id = 0; | ||
| 1064 | |||
| 1065 | if (connector) { | ||
| 1066 | struct radeon_connector *radeon_connector = to_radeon_connector(connector); | ||
| 1067 | struct radeon_connector_atom_dig *dig_connector = | ||
| 1068 | radeon_connector->con_priv; | ||
| 1069 | |||
| 1070 | dp_clock = dig_connector->dp_clock; | ||
| 1071 | dp_lane_count = dig_connector->dp_lane_count; | ||
| 1072 | connector_object_id = | ||
| 1073 | (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | memset(&args, 0, sizeof(args)); | ||
| 1077 | |||
| 1078 | if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) | ||
| 1079 | return; | ||
| 1080 | |||
| 1081 | switch (frev) { | ||
| 1082 | case 1: | ||
| 1083 | /* no params on frev 1 */ | ||
| 1084 | break; | ||
| 1085 | case 2: | ||
| 1086 | switch (crev) { | ||
| 1087 | case 1: | ||
| 1088 | case 2: | ||
| 1089 | args.v1.sDigEncoder.ucAction = action; | ||
| 1090 | args.v1.sDigEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); | ||
| 1091 | args.v1.sDigEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); | ||
| 1092 | |||
| 1093 | if (args.v1.sDigEncoder.ucEncoderMode == ATOM_ENCODER_MODE_DP) { | ||
| 1094 | if (dp_clock == 270000) | ||
| 1095 | args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; | ||
| 1096 | args.v1.sDigEncoder.ucLaneNum = dp_lane_count; | ||
| 1097 | } else if (radeon_encoder->pixel_clock > 165000) | ||
| 1098 | args.v1.sDigEncoder.ucLaneNum = 8; | ||
| 1099 | else | ||
| 1100 | args.v1.sDigEncoder.ucLaneNum = 4; | ||
| 1101 | break; | ||
| 1102 | default: | ||
| 1103 | DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); | ||
| 1104 | return; | ||
| 1105 | } | ||
| 1106 | break; | ||
| 1107 | default: | ||
| 1108 | DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); | ||
| 1109 | return; | ||
| 1110 | } | ||
| 1111 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); | ||
| 1112 | } | ||
| 1113 | |||
| 1024 | static void | 1114 | static void |
| 1025 | atombios_yuv_setup(struct drm_encoder *encoder, bool enable) | 1115 | atombios_yuv_setup(struct drm_encoder *encoder, bool enable) |
| 1026 | { | 1116 | { |
| @@ -1064,6 +1154,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) | |||
| 1064 | struct drm_device *dev = encoder->dev; | 1154 | struct drm_device *dev = encoder->dev; |
| 1065 | struct radeon_device *rdev = dev->dev_private; | 1155 | struct radeon_device *rdev = dev->dev_private; |
| 1066 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | 1156 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
| 1157 | struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); | ||
| 1067 | DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; | 1158 | DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; |
| 1068 | int index = 0; | 1159 | int index = 0; |
| 1069 | bool is_dig = false; | 1160 | bool is_dig = false; |
| @@ -1191,6 +1282,24 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) | |||
| 1191 | break; | 1282 | break; |
| 1192 | } | 1283 | } |
| 1193 | } | 1284 | } |
| 1285 | |||
| 1286 | if (ext_encoder) { | ||
| 1287 | int action; | ||
| 1288 | |||
| 1289 | switch (mode) { | ||
| 1290 | case DRM_MODE_DPMS_ON: | ||
| 1291 | default: | ||
| 1292 | action = ATOM_ENABLE; | ||
| 1293 | break; | ||
| 1294 | case DRM_MODE_DPMS_STANDBY: | ||
| 1295 | case DRM_MODE_DPMS_SUSPEND: | ||
| 1296 | case DRM_MODE_DPMS_OFF: | ||
| 1297 | action = ATOM_DISABLE; | ||
| 1298 | break; | ||
| 1299 | } | ||
| 1300 | atombios_external_encoder_setup(encoder, ext_encoder, action); | ||
| 1301 | } | ||
| 1302 | |||
| 1194 | radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); | 1303 | radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); |
| 1195 | 1304 | ||
| 1196 | } | 1305 | } |
| @@ -1438,6 +1547,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, | |||
| 1438 | struct drm_device *dev = encoder->dev; | 1547 | struct drm_device *dev = encoder->dev; |
| 1439 | struct radeon_device *rdev = dev->dev_private; | 1548 | struct radeon_device *rdev = dev->dev_private; |
| 1440 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | 1549 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
| 1550 | struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); | ||
| 1441 | 1551 | ||
| 1442 | radeon_encoder->pixel_clock = adjusted_mode->clock; | 1552 | radeon_encoder->pixel_clock = adjusted_mode->clock; |
| 1443 | 1553 | ||
| @@ -1498,6 +1608,11 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, | |||
| 1498 | } | 1608 | } |
| 1499 | break; | 1609 | break; |
| 1500 | } | 1610 | } |
| 1611 | |||
| 1612 | if (ext_encoder) { | ||
| 1613 | atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); | ||
| 1614 | } | ||
| 1615 | |||
| 1501 | atombios_apply_encoder_quirks(encoder, adjusted_mode); | 1616 | atombios_apply_encoder_quirks(encoder, adjusted_mode); |
| 1502 | 1617 | ||
| 1503 | if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { | 1618 | if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { |
| @@ -1698,6 +1813,53 @@ disable_done: | |||
| 1698 | radeon_encoder->active_device = 0; | 1813 | radeon_encoder->active_device = 0; |
| 1699 | } | 1814 | } |
| 1700 | 1815 | ||
| 1816 | /* these are handled by the primary encoders */ | ||
| 1817 | static void radeon_atom_ext_prepare(struct drm_encoder *encoder) | ||
| 1818 | { | ||
| 1819 | |||
| 1820 | } | ||
| 1821 | |||
| 1822 | static void radeon_atom_ext_commit(struct drm_encoder *encoder) | ||
| 1823 | { | ||
| 1824 | |||
| 1825 | } | ||
| 1826 | |||
| 1827 | static void | ||
| 1828 | radeon_atom_ext_mode_set(struct drm_encoder *encoder, | ||
| 1829 | struct drm_display_mode *mode, | ||
| 1830 | struct drm_display_mode *adjusted_mode) | ||
| 1831 | { | ||
| 1832 | |||
| 1833 | } | ||
| 1834 | |||
| 1835 | static void radeon_atom_ext_disable(struct drm_encoder *encoder) | ||
| 1836 | { | ||
| 1837 | |||
| 1838 | } | ||
| 1839 | |||
| 1840 | static void | ||
| 1841 | radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode) | ||
| 1842 | { | ||
| 1843 | |||
| 1844 | } | ||
| 1845 | |||
| 1846 | static bool radeon_atom_ext_mode_fixup(struct drm_encoder *encoder, | ||
| 1847 | struct drm_display_mode *mode, | ||
| 1848 | struct drm_display_mode *adjusted_mode) | ||
| 1849 | { | ||
| 1850 | return true; | ||
| 1851 | } | ||
| 1852 | |||
| 1853 | static const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = { | ||
| 1854 | .dpms = radeon_atom_ext_dpms, | ||
| 1855 | .mode_fixup = radeon_atom_ext_mode_fixup, | ||
| 1856 | .prepare = radeon_atom_ext_prepare, | ||
| 1857 | .mode_set = radeon_atom_ext_mode_set, | ||
| 1858 | .commit = radeon_atom_ext_commit, | ||
| 1859 | .disable = radeon_atom_ext_disable, | ||
| 1860 | /* no detect for TMDS/LVDS yet */ | ||
| 1861 | }; | ||
| 1862 | |||
| 1701 | static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { | 1863 | static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { |
| 1702 | .dpms = radeon_atom_encoder_dpms, | 1864 | .dpms = radeon_atom_encoder_dpms, |
| 1703 | .mode_fixup = radeon_atom_mode_fixup, | 1865 | .mode_fixup = radeon_atom_mode_fixup, |
| @@ -1807,6 +1969,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t | |||
| 1807 | radeon_encoder->devices = supported_device; | 1969 | radeon_encoder->devices = supported_device; |
| 1808 | radeon_encoder->rmx_type = RMX_OFF; | 1970 | radeon_encoder->rmx_type = RMX_OFF; |
| 1809 | radeon_encoder->underscan_type = UNDERSCAN_OFF; | 1971 | radeon_encoder->underscan_type = UNDERSCAN_OFF; |
| 1972 | radeon_encoder->is_ext_encoder = false; | ||
| 1810 | 1973 | ||
| 1811 | switch (radeon_encoder->encoder_id) { | 1974 | switch (radeon_encoder->encoder_id) { |
| 1812 | case ENCODER_OBJECT_ID_INTERNAL_LVDS: | 1975 | case ENCODER_OBJECT_ID_INTERNAL_LVDS: |
| @@ -1848,6 +2011,9 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t | |||
| 1848 | radeon_encoder->rmx_type = RMX_FULL; | 2011 | radeon_encoder->rmx_type = RMX_FULL; |
| 1849 | drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); | 2012 | drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); |
| 1850 | radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); | 2013 | radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); |
| 2014 | } else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) { | ||
| 2015 | drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); | ||
| 2016 | radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); | ||
| 1851 | } else { | 2017 | } else { |
| 1852 | drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); | 2018 | drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); |
| 1853 | radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); | 2019 | radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); |
| @@ -1856,5 +2022,22 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t | |||
| 1856 | } | 2022 | } |
| 1857 | drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); | 2023 | drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); |
| 1858 | break; | 2024 | break; |
| 2025 | case ENCODER_OBJECT_ID_SI170B: | ||
| 2026 | case ENCODER_OBJECT_ID_CH7303: | ||
| 2027 | case ENCODER_OBJECT_ID_EXTERNAL_SDVOA: | ||
| 2028 | case ENCODER_OBJECT_ID_EXTERNAL_SDVOB: | ||
| 2029 | case ENCODER_OBJECT_ID_TITFP513: | ||
| 2030 | case ENCODER_OBJECT_ID_VT1623: | ||
| 2031 | case ENCODER_OBJECT_ID_HDMI_SI1930: | ||
| 2032 | /* these are handled by the primary encoders */ | ||
| 2033 | radeon_encoder->is_ext_encoder = true; | ||
| 2034 | if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) | ||
| 2035 | drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); | ||
| 2036 | else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) | ||
| 2037 | drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); | ||
| 2038 | else | ||
| 2039 | drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); | ||
| 2040 | drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs); | ||
| 2041 | break; | ||
| 1859 | } | 2042 | } |
| 1860 | } | 2043 | } |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 663bc51cf99e..e301c6f9e059 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
| @@ -375,6 +375,7 @@ struct radeon_encoder { | |||
| 375 | int hdmi_config_offset; | 375 | int hdmi_config_offset; |
| 376 | int hdmi_audio_workaround; | 376 | int hdmi_audio_workaround; |
| 377 | int hdmi_buffer_status; | 377 | int hdmi_buffer_status; |
| 378 | bool is_ext_encoder; | ||
| 378 | }; | 379 | }; |
| 379 | 380 | ||
| 380 | struct radeon_connector_atom_dig { | 381 | struct radeon_connector_atom_dig { |
