Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amd/display: Enable Freesync over PCon

[why]
Enable Freesync over PCon on Linux environment.

[how]
Adding Freesync over PCon support in amdgpu_dm
- Read DPCD for Freesync over PCon capabilitiy
- Add whitelist for compatible branch devices

Reviewed-by: Chao-kai Wang <Stylon.Wang@amd.com>
Acked-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Sung Joon Kim <sungkim@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Sung Joon Kim and committed by
Alex Deucher
5b49da02 634d0aa5

+118 -37
+43 -2
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
··· 106 106 107 107 #include "modules/inc/mod_freesync.h" 108 108 #include "modules/power/power_helpers.h" 109 - #include "modules/inc/mod_info_packet.h" 110 109 111 110 #define FIRMWARE_RENOIR_DMUB "amdgpu/renoir_dmcub.bin" 112 111 MODULE_FIRMWARE(FIRMWARE_RENOIR_DMUB); ··· 7112 7113 aconnector->base.dpms = DRM_MODE_DPMS_OFF; 7113 7114 aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */ 7114 7115 aconnector->audio_inst = -1; 7116 + aconnector->pack_sdp_v1_3 = false; 7117 + aconnector->as_type = ADAPTIVE_SYNC_TYPE_NONE; 7118 + memset(&aconnector->vsdb_info, 0, sizeof(aconnector->vsdb_info)); 7115 7119 mutex_init(&aconnector->hpd_lock); 7116 7120 7117 7121 /* ··· 7605 7603 struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_crtc_state->base.crtc); 7606 7604 unsigned long flags; 7607 7605 bool pack_sdp_v1_3 = false; 7606 + struct amdgpu_dm_connector *aconn; 7607 + enum vrr_packet_type packet_type = PACKET_TYPE_VRR; 7608 7608 7609 7609 if (!new_stream) 7610 7610 return; ··· 7642 7638 } 7643 7639 } 7644 7640 7641 + aconn = (struct amdgpu_dm_connector *)new_stream->dm_stream_context; 7642 + 7643 + if (aconn && aconn->as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) { 7644 + pack_sdp_v1_3 = aconn->pack_sdp_v1_3; 7645 + 7646 + if (aconn->vsdb_info.amd_vsdb_version == 1) 7647 + packet_type = PACKET_TYPE_FS_V1; 7648 + else if (aconn->vsdb_info.amd_vsdb_version == 2) 7649 + packet_type = PACKET_TYPE_FS_V2; 7650 + else if (aconn->vsdb_info.amd_vsdb_version == 3) 7651 + packet_type = PACKET_TYPE_FS_V3; 7652 + 7653 + mod_build_adaptive_sync_infopacket(new_stream, aconn->as_type, NULL, 7654 + &new_stream->adaptive_sync_infopacket); 7655 + } 7656 + 7645 7657 mod_freesync_build_vrr_infopacket( 7646 7658 dm->freesync_module, 7647 7659 new_stream, 7648 7660 &vrr_params, 7649 - PACKET_TYPE_VRR, 7661 + packet_type, 7650 7662 TRANSFER_FUNC_UNKNOWN, 7651 7663 &vrr_infopacket, 7652 7664 pack_sdp_v1_3); ··· 10331 10311 struct amdgpu_device *adev = drm_to_adev(dev); 10332 10312 struct amdgpu_hdmi_vsdb_info vsdb_info = {0}; 10333 10313 bool freesync_capable = false; 10314 + enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE; 10334 10315 10335 10316 if (!connector->state) { 10336 10317 DRM_ERROR("%s - Connector has no state", __func__); ··· 10413 10392 if (i >= 0 && vsdb_info.freesync_supported) { 10414 10393 timing = &edid->detailed_timings[i]; 10415 10394 data = &timing->data.other_data; 10395 + 10396 + amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz; 10397 + amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz; 10398 + if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) 10399 + freesync_capable = true; 10400 + 10401 + connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz; 10402 + connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz; 10403 + } 10404 + } 10405 + 10406 + as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link); 10407 + 10408 + if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) { 10409 + i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info); 10410 + if (i >= 0 && vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) { 10411 + 10412 + amdgpu_dm_connector->pack_sdp_v1_3 = true; 10413 + amdgpu_dm_connector->as_type = as_type; 10414 + amdgpu_dm_connector->vsdb_info = vsdb_info; 10416 10415 10417 10416 amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz; 10418 10417 amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
+36 -31
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
··· 59 59 #include "irq_types.h" 60 60 #include "signal_types.h" 61 61 #include "amdgpu_dm_crc.h" 62 + #include "mod_info_packet.h" 62 63 struct aux_payload; 63 64 struct set_config_cmd_payload; 64 65 enum aux_return_code_type; ··· 578 577 MST_CLEAR_ALLOCATED_PAYLOAD = BIT(3), 579 578 }; 580 579 580 + /** 581 + * struct amdgpu_hdmi_vsdb_info - Keep track of the VSDB info 582 + * 583 + * AMDGPU supports FreeSync over HDMI by using the VSDB section, and this 584 + * struct is useful to keep track of the display-specific information about 585 + * FreeSync. 586 + */ 587 + struct amdgpu_hdmi_vsdb_info { 588 + /** 589 + * @amd_vsdb_version: Vendor Specific Data Block Version, should be 590 + * used to determine which Vendor Specific InfoFrame (VSIF) to send. 591 + */ 592 + unsigned int amd_vsdb_version; 593 + 594 + /** 595 + * @freesync_supported: FreeSync Supported. 596 + */ 597 + bool freesync_supported; 598 + 599 + /** 600 + * @min_refresh_rate_hz: FreeSync Minimum Refresh Rate in Hz. 601 + */ 602 + unsigned int min_refresh_rate_hz; 603 + 604 + /** 605 + * @max_refresh_rate_hz: FreeSync Maximum Refresh Rate in Hz 606 + */ 607 + unsigned int max_refresh_rate_hz; 608 + }; 609 + 581 610 struct amdgpu_dm_connector { 582 611 583 612 struct drm_connector base; ··· 680 649 /* Automated testing */ 681 650 bool timing_changed; 682 651 struct dc_crtc_timing *timing_requested; 652 + 653 + /* Adaptive Sync */ 654 + bool pack_sdp_v1_3; 655 + enum adaptive_sync_type as_type; 656 + struct amdgpu_hdmi_vsdb_info vsdb_info; 683 657 }; 684 658 685 659 static inline void amdgpu_dm_set_mst_status(uint8_t *status, ··· 754 718 int vcpi_slots; 755 719 uint64_t pbn; 756 720 }; 757 - 758 - /** 759 - * struct amdgpu_hdmi_vsdb_info - Keep track of the VSDB info 760 - * 761 - * AMDGPU supports FreeSync over HDMI by using the VSDB section, and this 762 - * struct is useful to keep track of the display-specific information about 763 - * FreeSync. 764 - */ 765 - struct amdgpu_hdmi_vsdb_info { 766 - /** 767 - * @amd_vsdb_version: Vendor Specific Data Block Version, should be 768 - * used to determine which Vendor Specific InfoFrame (VSIF) to send. 769 - */ 770 - unsigned int amd_vsdb_version; 771 - 772 - /** 773 - * @freesync_supported: FreeSync Supported. 774 - */ 775 - bool freesync_supported; 776 - 777 - /** 778 - * @min_refresh_rate_hz: FreeSync Minimum Refresh Rate in Hz. 779 - */ 780 - unsigned int min_refresh_rate_hz; 781 - 782 - /** 783 - * @max_refresh_rate_hz: FreeSync Maximum Refresh Rate in Hz 784 - */ 785 - unsigned int max_refresh_rate_hz; 786 - }; 787 - 788 721 789 722 #define to_dm_connector_state(x)\ 790 723 container_of((x), struct dm_connector_state, base)
+33
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
··· 1133 1133 // TODO 1134 1134 } 1135 1135 1136 + static bool dm_is_freesync_pcon_whitelist(const uint32_t branch_dev_id) 1137 + { 1138 + bool ret_val = false; 1139 + 1140 + switch (branch_dev_id) { 1141 + case DP_BRANCH_DEVICE_ID_0060AD: 1142 + ret_val = true; 1143 + break; 1144 + default: 1145 + break; 1146 + } 1147 + 1148 + return ret_val; 1149 + } 1150 + 1151 + enum adaptive_sync_type dm_get_adaptive_sync_support_type(struct dc_link *link) 1152 + { 1153 + struct dpcd_caps *dpcd_caps = &link->dpcd_caps; 1154 + enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE; 1155 + 1156 + switch (dpcd_caps->dongle_type) { 1157 + case DISPLAY_DONGLE_DP_HDMI_CONVERTER: 1158 + if (dpcd_caps->adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT == true && 1159 + dpcd_caps->allow_invalid_MSA_timing_param == true && 1160 + dm_is_freesync_pcon_whitelist(dpcd_caps->branch_dev_id)) 1161 + as_type = FREESYNC_TYPE_PCON_IN_WHITELIST; 1162 + break; 1163 + default: 1164 + break; 1165 + } 1166 + 1167 + return as_type; 1168 + }
+1
drivers/gpu/drm/amd/display/dc/dm_helpers.h
··· 199 199 const struct dc_link *link, 200 200 struct set_config_cmd_payload *payload, 201 201 enum set_config_status *operation_result); 202 + enum adaptive_sync_type dm_get_adaptive_sync_support_type(struct dc_link *link); 202 203 203 204 enum dc_edid_status dm_helpers_get_sbios_edid(struct dc_link *link, struct dc_edid *edid); 204 205
+1
drivers/gpu/drm/amd/display/include/ddc_service_types.h
··· 35 35 #define DP_BRANCH_DEVICE_ID_00E04C 0x00E04C 36 36 #define DP_BRANCH_DEVICE_ID_006037 0x006037 37 37 #define DP_BRANCH_DEVICE_ID_001CF8 0x001CF8 38 + #define DP_BRANCH_DEVICE_ID_0060AD 0x0060AD 38 39 #define DP_BRANCH_HW_REV_10 0x10 39 40 #define DP_BRANCH_HW_REV_20 0x20 40 41
+2 -2
drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
··· 44 44 enum adaptive_sync_type { 45 45 ADAPTIVE_SYNC_TYPE_NONE = 0, 46 46 ADAPTIVE_SYNC_TYPE_DP = 1, 47 - ADAPTIVE_SYNC_TYPE_PCON_IN_WHITELIST = 2, 48 - ADAPTIVE_SYNC_TYPE_PCON_NOT_IN_WHITELIST = 3, 47 + FREESYNC_TYPE_PCON_IN_WHITELIST = 2, 48 + FREESYNC_TYPE_PCON_NOT_IN_WHITELIST = 3, 49 49 ADAPTIVE_SYNC_TYPE_EDP = 4, 50 50 }; 51 51
+2 -2
drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
··· 533 533 if (stream != NULL) 534 534 mod_build_adaptive_sync_infopacket_v2(stream, param, info_packet); 535 535 break; 536 - case ADAPTIVE_SYNC_TYPE_PCON_IN_WHITELIST: 536 + case FREESYNC_TYPE_PCON_IN_WHITELIST: 537 537 mod_build_adaptive_sync_infopacket_v1(info_packet); 538 538 break; 539 539 case ADAPTIVE_SYNC_TYPE_NONE: 540 - case ADAPTIVE_SYNC_TYPE_PCON_NOT_IN_WHITELIST: 540 + case FREESYNC_TYPE_PCON_NOT_IN_WHITELIST: 541 541 default: 542 542 break; 543 543 }