Commit 5b49da02 authored by Sung Joon Kim's avatar Sung Joon Kim Committed by Alex Deucher
Browse files

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: default avatarChao-kai Wang <Stylon.Wang@amd.com>
Acked-by: default avatarAlex Hung <alex.hung@amd.com>
Signed-off-by: default avatarSung Joon Kim <sungkim@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 634d0aa5
Loading
Loading
Loading
Loading
+43 −2
Original line number Diff line number Diff line
@@ -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;
+36 −31
Original line number Diff line number Diff line
@@ -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)

+33 −0
Original line number Diff line number Diff line
@@ -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;
}
+1 −0
Original line number Diff line number Diff line
@@ -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);

+1 −0
Original line number Diff line number Diff line
@@ -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

Loading