mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 18:30:06 +00:00
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>
This commit is contained in:
parent
634d0aa54e
commit
5b49da02dd
7 changed files with 118 additions and 37 deletions
|
@ -106,7 +106,6 @@
|
|||
|
||||
#include "modules/inc/mod_freesync.h"
|
||||
#include "modules/power/power_helpers.h"
|
||||
#include "modules/inc/mod_info_packet.h"
|
||||
|
||||
#define FIRMWARE_RENOIR_DMUB "amdgpu/renoir_dmcub.bin"
|
||||
MODULE_FIRMWARE(FIRMWARE_RENOIR_DMUB);
|
||||
|
@ -7113,6 +7112,9 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
|
|||
aconnector->base.dpms = DRM_MODE_DPMS_OFF;
|
||||
aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */
|
||||
aconnector->audio_inst = -1;
|
||||
aconnector->pack_sdp_v1_3 = false;
|
||||
aconnector->as_type = ADAPTIVE_SYNC_TYPE_NONE;
|
||||
memset(&aconnector->vsdb_info, 0, sizeof(aconnector->vsdb_info));
|
||||
mutex_init(&aconnector->hpd_lock);
|
||||
|
||||
/*
|
||||
|
@ -7603,6 +7605,8 @@ static void update_freesync_state_on_stream(
|
|||
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_crtc_state->base.crtc);
|
||||
unsigned long flags;
|
||||
bool pack_sdp_v1_3 = false;
|
||||
struct amdgpu_dm_connector *aconn;
|
||||
enum vrr_packet_type packet_type = PACKET_TYPE_VRR;
|
||||
|
||||
if (!new_stream)
|
||||
return;
|
||||
|
@ -7638,11 +7642,27 @@ static void update_freesync_state_on_stream(
|
|||
}
|
||||
}
|
||||
|
||||
aconn = (struct amdgpu_dm_connector *)new_stream->dm_stream_context;
|
||||
|
||||
if (aconn && aconn->as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) {
|
||||
pack_sdp_v1_3 = aconn->pack_sdp_v1_3;
|
||||
|
||||
if (aconn->vsdb_info.amd_vsdb_version == 1)
|
||||
packet_type = PACKET_TYPE_FS_V1;
|
||||
else if (aconn->vsdb_info.amd_vsdb_version == 2)
|
||||
packet_type = PACKET_TYPE_FS_V2;
|
||||
else if (aconn->vsdb_info.amd_vsdb_version == 3)
|
||||
packet_type = PACKET_TYPE_FS_V3;
|
||||
|
||||
mod_build_adaptive_sync_infopacket(new_stream, aconn->as_type, NULL,
|
||||
&new_stream->adaptive_sync_infopacket);
|
||||
}
|
||||
|
||||
mod_freesync_build_vrr_infopacket(
|
||||
dm->freesync_module,
|
||||
new_stream,
|
||||
&vrr_params,
|
||||
PACKET_TYPE_VRR,
|
||||
packet_type,
|
||||
TRANSFER_FUNC_UNKNOWN,
|
||||
&vrr_infopacket,
|
||||
pack_sdp_v1_3);
|
||||
|
@ -10311,6 +10331,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
|
|||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
|
||||
bool freesync_capable = false;
|
||||
enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
|
||||
|
||||
if (!connector->state) {
|
||||
DRM_ERROR("%s - Connector has no state", __func__);
|
||||
|
@ -10403,6 +10424,26 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
|
|||
}
|
||||
}
|
||||
|
||||
as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link);
|
||||
|
||||
if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) {
|
||||
i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
|
||||
if (i >= 0 && vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) {
|
||||
|
||||
amdgpu_dm_connector->pack_sdp_v1_3 = true;
|
||||
amdgpu_dm_connector->as_type = as_type;
|
||||
amdgpu_dm_connector->vsdb_info = vsdb_info;
|
||||
|
||||
amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
|
||||
amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
|
||||
if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
|
||||
freesync_capable = true;
|
||||
|
||||
connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
|
||||
connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
|
||||
}
|
||||
}
|
||||
|
||||
update:
|
||||
if (dm_con_state)
|
||||
dm_con_state->freesync_capable = freesync_capable;
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#include "irq_types.h"
|
||||
#include "signal_types.h"
|
||||
#include "amdgpu_dm_crc.h"
|
||||
#include "mod_info_packet.h"
|
||||
struct aux_payload;
|
||||
struct set_config_cmd_payload;
|
||||
enum aux_return_code_type;
|
||||
|
@ -577,6 +578,36 @@ enum mst_progress_status {
|
|||
MST_CLEAR_ALLOCATED_PAYLOAD = BIT(3),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct amdgpu_hdmi_vsdb_info - Keep track of the VSDB info
|
||||
*
|
||||
* AMDGPU supports FreeSync over HDMI by using the VSDB section, and this
|
||||
* struct is useful to keep track of the display-specific information about
|
||||
* FreeSync.
|
||||
*/
|
||||
struct amdgpu_hdmi_vsdb_info {
|
||||
/**
|
||||
* @amd_vsdb_version: Vendor Specific Data Block Version, should be
|
||||
* used to determine which Vendor Specific InfoFrame (VSIF) to send.
|
||||
*/
|
||||
unsigned int amd_vsdb_version;
|
||||
|
||||
/**
|
||||
* @freesync_supported: FreeSync Supported.
|
||||
*/
|
||||
bool freesync_supported;
|
||||
|
||||
/**
|
||||
* @min_refresh_rate_hz: FreeSync Minimum Refresh Rate in Hz.
|
||||
*/
|
||||
unsigned int min_refresh_rate_hz;
|
||||
|
||||
/**
|
||||
* @max_refresh_rate_hz: FreeSync Maximum Refresh Rate in Hz
|
||||
*/
|
||||
unsigned int max_refresh_rate_hz;
|
||||
};
|
||||
|
||||
struct amdgpu_dm_connector {
|
||||
|
||||
struct drm_connector base;
|
||||
|
@ -649,6 +680,11 @@ struct amdgpu_dm_connector {
|
|||
/* Automated testing */
|
||||
bool timing_changed;
|
||||
struct dc_crtc_timing *timing_requested;
|
||||
|
||||
/* Adaptive Sync */
|
||||
bool pack_sdp_v1_3;
|
||||
enum adaptive_sync_type as_type;
|
||||
struct amdgpu_hdmi_vsdb_info vsdb_info;
|
||||
};
|
||||
|
||||
static inline void amdgpu_dm_set_mst_status(uint8_t *status,
|
||||
|
@ -719,37 +755,6 @@ struct dm_connector_state {
|
|||
uint64_t pbn;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct amdgpu_hdmi_vsdb_info - Keep track of the VSDB info
|
||||
*
|
||||
* AMDGPU supports FreeSync over HDMI by using the VSDB section, and this
|
||||
* struct is useful to keep track of the display-specific information about
|
||||
* FreeSync.
|
||||
*/
|
||||
struct amdgpu_hdmi_vsdb_info {
|
||||
/**
|
||||
* @amd_vsdb_version: Vendor Specific Data Block Version, should be
|
||||
* used to determine which Vendor Specific InfoFrame (VSIF) to send.
|
||||
*/
|
||||
unsigned int amd_vsdb_version;
|
||||
|
||||
/**
|
||||
* @freesync_supported: FreeSync Supported.
|
||||
*/
|
||||
bool freesync_supported;
|
||||
|
||||
/**
|
||||
* @min_refresh_rate_hz: FreeSync Minimum Refresh Rate in Hz.
|
||||
*/
|
||||
unsigned int min_refresh_rate_hz;
|
||||
|
||||
/**
|
||||
* @max_refresh_rate_hz: FreeSync Maximum Refresh Rate in Hz
|
||||
*/
|
||||
unsigned int max_refresh_rate_hz;
|
||||
};
|
||||
|
||||
|
||||
#define to_dm_connector_state(x)\
|
||||
container_of((x), struct dm_connector_state, base)
|
||||
|
||||
|
|
|
@ -1133,3 +1133,36 @@ void dm_helpers_dp_mst_update_branch_bandwidth(
|
|||
// TODO
|
||||
}
|
||||
|
||||
static bool dm_is_freesync_pcon_whitelist(const uint32_t branch_dev_id)
|
||||
{
|
||||
bool ret_val = false;
|
||||
|
||||
switch (branch_dev_id) {
|
||||
case DP_BRANCH_DEVICE_ID_0060AD:
|
||||
ret_val = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
enum adaptive_sync_type dm_get_adaptive_sync_support_type(struct dc_link *link)
|
||||
{
|
||||
struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
|
||||
enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
|
||||
|
||||
switch (dpcd_caps->dongle_type) {
|
||||
case DISPLAY_DONGLE_DP_HDMI_CONVERTER:
|
||||
if (dpcd_caps->adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT == true &&
|
||||
dpcd_caps->allow_invalid_MSA_timing_param == true &&
|
||||
dm_is_freesync_pcon_whitelist(dpcd_caps->branch_dev_id))
|
||||
as_type = FREESYNC_TYPE_PCON_IN_WHITELIST;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return as_type;
|
||||
}
|
||||
|
|
|
@ -199,6 +199,7 @@ int dm_helpers_dmub_set_config_sync(struct dc_context *ctx,
|
|||
const struct dc_link *link,
|
||||
struct set_config_cmd_payload *payload,
|
||||
enum set_config_status *operation_result);
|
||||
enum adaptive_sync_type dm_get_adaptive_sync_support_type(struct dc_link *link);
|
||||
|
||||
enum dc_edid_status dm_helpers_get_sbios_edid(struct dc_link *link, struct dc_edid *edid);
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#define DP_BRANCH_DEVICE_ID_00E04C 0x00E04C
|
||||
#define DP_BRANCH_DEVICE_ID_006037 0x006037
|
||||
#define DP_BRANCH_DEVICE_ID_001CF8 0x001CF8
|
||||
#define DP_BRANCH_DEVICE_ID_0060AD 0x0060AD
|
||||
#define DP_BRANCH_HW_REV_10 0x10
|
||||
#define DP_BRANCH_HW_REV_20 0x20
|
||||
|
||||
|
|
|
@ -44,8 +44,8 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
|
|||
enum adaptive_sync_type {
|
||||
ADAPTIVE_SYNC_TYPE_NONE = 0,
|
||||
ADAPTIVE_SYNC_TYPE_DP = 1,
|
||||
ADAPTIVE_SYNC_TYPE_PCON_IN_WHITELIST = 2,
|
||||
ADAPTIVE_SYNC_TYPE_PCON_NOT_IN_WHITELIST = 3,
|
||||
FREESYNC_TYPE_PCON_IN_WHITELIST = 2,
|
||||
FREESYNC_TYPE_PCON_NOT_IN_WHITELIST = 3,
|
||||
ADAPTIVE_SYNC_TYPE_EDP = 4,
|
||||
};
|
||||
|
||||
|
|
|
@ -533,11 +533,11 @@ void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
|
|||
if (stream != NULL)
|
||||
mod_build_adaptive_sync_infopacket_v2(stream, param, info_packet);
|
||||
break;
|
||||
case ADAPTIVE_SYNC_TYPE_PCON_IN_WHITELIST:
|
||||
case FREESYNC_TYPE_PCON_IN_WHITELIST:
|
||||
mod_build_adaptive_sync_infopacket_v1(info_packet);
|
||||
break;
|
||||
case ADAPTIVE_SYNC_TYPE_NONE:
|
||||
case ADAPTIVE_SYNC_TYPE_PCON_NOT_IN_WHITELIST:
|
||||
case FREESYNC_TYPE_PCON_NOT_IN_WHITELIST:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue