Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
df47421
[FROM-ML] drm/amd/display: Return if DisplayID not found in parse_amd…
Lawstorant Feb 3, 2026
f755cd0
[FROM-ML] drm/amd/display: Refactor amdgpu_dm_update_freesync_caps()
Lawstorant Feb 3, 2026
b33f640
[FROM-ML] drm/amd/display: Check for VRR range in CEA AMD vsdb
Lawstorant Feb 3, 2026
f7e80a4
[FROM-ML] drm/amd/display: Use bigger VRR range if found in AMD vsdb
Lawstorant Feb 3, 2026
fd22189
[FROM-ML] drm/amd/display: Refactor PCON VRR compatibility check
Lawstorant Feb 3, 2026
6089fe9
[FROM-ML] drm/amd/display: Add PCON VRR ID check override
Lawstorant Feb 3, 2026
5e007f7
[FROM-ML] drm/amd/display: Add CH7218 PCON ID
Lawstorant Feb 3, 2026
72a5beb
[FROM-ML] drm/edid: Parse more info from HDMI Forum vsdb
Lawstorant Feb 3, 2026
6531fec
[FROM-ML] drm/amd/display: Rename PCON adaptive sync types
Lawstorant Feb 3, 2026
75e4c16
[FROM-ML] drm/amd/display: Enable HDMI VRR over PCON
Lawstorant Feb 3, 2026
d90fba5
[FROM-ML] drm/amd/display: Support HDMI VRRmax=0
Lawstorant Feb 3, 2026
4a8f620
[FROM-ML] drm/amd/display: Build HDMI vsif in correct slot
Lawstorant Feb 3, 2026
bd9c923
[FROM-ML] drm/amd/display: Save HDMI gaming info to edid caps
Lawstorant Feb 3, 2026
1269ebc
[FROM-ML] drm/amd/display: Restore ALLM support in HDMI vsif
Lawstorant Feb 3, 2026
47b0301
[FROM-ML] drm/amd/display: Trigger ALLM if it's available
Lawstorant Feb 3, 2026
fae1544
[FROM-ML] drm/amd/display: Add parameter to control ALLM behavior
Lawstorant Feb 3, 2026
9a24bba
[FROM-ML] drm/amd/display: Reintroduce VTEM info frame
Lawstorant Feb 3, 2026
fd09ba3
[FROM-ML] drm/amd/display: Enable HDMI VRR
Lawstorant Feb 3, 2026
b252e03
[FROM-ML] drm/amd/display: Add HDMI VRR desktop mode
Lawstorant Feb 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions drivers/gpu/drm/amd/amdgpu/amdgpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ extern int amdgpu_rebar;

extern int amdgpu_wbrf;
extern int amdgpu_user_queue;
extern uint amdgpu_allm_mode;
extern bool amdgpu_hdmi_vrr_desktop_mode;

extern uint amdgpu_hdmi_hpd_debounce_delay_ms;

Expand Down
27 changes: 26 additions & 1 deletion drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ int amdgpu_umsch_mm_fwlog;
int amdgpu_rebar = -1; /* auto */
int amdgpu_user_queue = -1;
uint amdgpu_hdmi_hpd_debounce_delay_ms;
uint amdgpu_allm_mode = 1;
bool amdgpu_hdmi_vrr_desktop_mode = true;

DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
"DRM_UT_CORE",
Expand Down Expand Up @@ -1124,7 +1126,7 @@ module_param_named(rebar, amdgpu_rebar, int, 0444);
MODULE_PARM_DESC(user_queue, "Enable user queues (-1 = auto (default), 0 = disable, 1 = enable, 2 = enable UQs and disable KQs)");
module_param_named(user_queue, amdgpu_user_queue, int, 0444);

/*
/**
* DOC: hdmi_hpd_debounce_delay_ms (uint)
* HDMI HPD disconnect debounce delay in milliseconds.
*
Expand All @@ -1134,6 +1136,29 @@ module_param_named(user_queue, amdgpu_user_queue, int, 0444);
MODULE_PARM_DESC(hdmi_hpd_debounce_delay_ms, "HDMI HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms, uint, 0644);

/**
* DOC: allm_mode (int)
* Changes ALLM triggering mode (if sink supports ALLM). Possible values:
*
* - 0 = ALLM disabled
* - 1 = ALLM dynamically triggered based on VRR state / Game Content Type Hint
* - 2 = ALLM forced always on
*/
MODULE_PARM_DESC(allm_mode, "Changes ALLM trigger mode (0 = disable, 1 = enable (default), 2 = force enable)");
module_param_named(allm_mode, amdgpu_allm_mode, uint, 0644);

/**
* DOC: hdmi_vrr_on_dekstop (bool)
* Enables FreeSync behavior mimicking by keeping HDMI VRR signalling active in
* fixed refresh rate conditions like normal desktop work/web browsing.
* Possible values:
*
* - false = HDMI VRR is only enabled if refresh rate is truly variable
* - true = Mimics FreeSync behavior and keeps HDMI VRR always active
*/
MODULE_PARM_DESC(hdmi_vrr_desktop_mode, "Changes HDMI VRR desktop mode (false = disable, true = enable (default))");
module_param_named(hdmi_vrr_desktop_mode, amdgpu_hdmi_vrr_desktop_mode, bool, 0644);

/* These devices are not supported by amdgpu.
* They are supported by the mach64, r128, radeon drivers
*/
Expand Down
205 changes: 151 additions & 54 deletions drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2069,6 +2069,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
if (amdgpu_dc_debug_mask & DC_SKIP_DETECTION_LT)
adev->dm.dc->debug.skip_detection_link_training = true;

if (amdgpu_dc_debug_mask & DC_OVERRIDE_PCON_VRR_ID_CHECK)
adev->dm.dc->debug.override_pcon_vrr_id_check = true;

adev->dm.dc->debug.visual_confirm = amdgpu_dc_visual_confirm;

/* TODO: Remove after DP2 receiver gets proper support of Cable ID feature */
Expand Down Expand Up @@ -7370,7 +7373,7 @@ create_stream_for_sink(struct drm_connector *connector,
update_stream_signal(stream, sink);

if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket);
mod_build_hf_vsif_infopacket(stream, &stream->hfvsif_infopacket);

if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
Expand Down Expand Up @@ -9607,7 +9610,11 @@ 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 || aconn->vsdb_info.replay_mode)) {
if (aconn && aconn->as_type == ADAPTIVE_SYNC_TYPE_HDMI)
packet_type = PACKET_TYPE_VTEM;

else if (aconn && (aconn->as_type == ADAPTIVE_SYNC_TYPE_PCON_ALLOWED ||
aconn->vsdb_info.replay_mode)) {
pack_sdp_v1_3 = aconn->pack_sdp_v1_3;

if (aconn->vsdb_info.amd_vsdb_version == 1)
Expand Down Expand Up @@ -13109,8 +13116,8 @@ static void parse_edid_displayid_vrr(struct drm_connector *connector,
}
}

static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
const struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info)
static int parse_amd_vsdb_did(struct amdgpu_dm_connector *aconnector,
const struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info)
{
u8 *edid_ext = NULL;
int i;
Expand All @@ -13126,6 +13133,9 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
break;
}

if (i == edid->extensions)
return false;

while (j < EDID_LENGTH - sizeof(struct amd_vsdb_block)) {
struct amd_vsdb_block *amd_vsdb = (struct amd_vsdb_block *)&edid_ext[j];
unsigned int ieeeId = (amd_vsdb->ieee_id[2] << 16) | (amd_vsdb->ieee_id[1] << 8) | (amd_vsdb->ieee_id[0]);
Expand All @@ -13144,13 +13154,13 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
return false;
}

static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
const struct edid *edid,
struct amdgpu_hdmi_vsdb_info *vsdb_info)
static int parse_amd_vsdb_cea(struct amdgpu_dm_connector *aconnector,
const struct edid *edid,
struct amdgpu_hdmi_vsdb_info *vsdb_info)
{
struct amdgpu_hdmi_vsdb_info vsdb_local = {0};
u8 *edid_ext = NULL;
int i;
bool valid_vsdb_found = false;

/*----- drm_find_cea_extension() -----*/
/* No EDID or EDID extensions */
Expand All @@ -13171,9 +13181,83 @@ static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
if (edid_ext[0] != CEA_EXT)
return -ENODEV;

valid_vsdb_found = parse_edid_cea(aconnector, edid_ext, EDID_LENGTH, vsdb_info);
if (!parse_edid_cea(aconnector, edid_ext, EDID_LENGTH, &vsdb_local))
return -ENODEV;

*vsdb_info = vsdb_local;
return i;
}

static bool is_monitor_range_invalid(const struct drm_connector *conn)
{
return conn->display_info.monitor_range.min_vfreq == 0 ||
conn->display_info.monitor_range.max_vfreq == 0;
}

return valid_vsdb_found ? i : -ENODEV;
/*
* Returns true if (max_vfreq - min_vfreq) > 10
*/
static bool is_freesync_capable(const struct drm_monitor_range_info *range)
{
return (range->max_vfreq - range->min_vfreq) > 10;
}

static void monitor_range_from_vsdb(struct drm_display_info *display,
const struct amdgpu_hdmi_vsdb_info *vsdb)
{
display->monitor_range.min_vfreq = vsdb->min_refresh_rate_hz;
display->monitor_range.max_vfreq = vsdb->max_refresh_rate_hz;
}

/**
* Get VRR range from HDMI VRR info in EDID. If VRRmax == 0,
* try getting upper bound from AMD vsdb.
*
* @conn: drm_connector with HDMI VRR info
* @vsdb: AMD vsdb from CAE
*/
static void monitor_range_from_hdmi(struct drm_display_info *display,
const struct amdgpu_hdmi_vsdb_info *vsdb)
{
u16 vrr_max = display->hdmi.vrr_cap.vrr_max;

/* Try getting upper vrr bound from AMD vsdb */
if (vrr_max == 0)
vrr_max = vsdb->max_refresh_rate_hz;

/* Use max possible BRR value as a last resort */
if (vrr_max == 0)
vrr_max = VTEM_BRR_MAX;

display->monitor_range.min_vfreq = display->hdmi.vrr_cap.vrr_min;
display->monitor_range.max_vfreq = vrr_max;
}

/*
* Returns true if connector is capable of freesync
* Optionally, can fetch the range from AMD vsdb
*/
static bool copy_range_to_amdgpu_connector(struct drm_connector *conn)
{
struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(conn);
struct drm_monitor_range_info *range = &conn->display_info.monitor_range;

aconn->min_vfreq = range->min_vfreq;
aconn->max_vfreq = range->max_vfreq;

return is_freesync_capable(range);
}

/*
* Returns true if range from AMD vsdb is bigger
*/
static bool compare_ranges(struct drm_connector *conn,
struct amdgpu_hdmi_vsdb_info *vsdb)
{
struct drm_monitor_range_info *range = &conn->display_info.monitor_range;

return (vsdb->max_refresh_rate_hz - vsdb->min_refresh_rate_hz) >
(range->max_vfreq - range->min_vfreq);
}

/**
Expand All @@ -13190,16 +13274,19 @@ static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
const struct drm_edid *drm_edid)
{
int i = 0;
struct amdgpu_dm_connector *amdgpu_dm_connector =
to_amdgpu_dm_connector(connector);
struct dm_connector_state *dm_con_state = NULL;
struct dc_sink *sink;
struct amdgpu_device *adev = drm_to_adev(connector->dev);
struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
struct amdgpu_hdmi_vsdb_info vsdb_did = {0};
struct drm_hdmi_vrr_cap hdmi_vrr = {0};
struct dpcd_caps dpcd_caps = {0};
const struct edid *edid;
bool freesync_capable = false;
enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
bool pcon_allowed = false;
bool is_pcon = false;

if (!connector->state) {
drm_err(adev_to_drm(adev), "%s - Connector has no state", __func__);
Expand Down Expand Up @@ -13227,63 +13314,73 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
if (!adev->dm.freesync_module || !dc_supports_vrr(sink->ctx->dce_version))
goto update;

/* Gather all data */
edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
parse_amd_vsdb_cea(amdgpu_dm_connector, edid, &vsdb_info);
hdmi_vrr = connector->display_info.hdmi.vrr_cap;

if (amdgpu_dm_connector->dc_link) {
dpcd_caps = amdgpu_dm_connector->dc_link->dpcd_caps;
is_pcon = dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER;
pcon_allowed = dm_helpers_is_vrr_pcon_allowed(
amdgpu_dm_connector->dc_link, connector->dev);
}

/* Some eDP panels only have the refresh rate range info in DisplayID */
if ((connector->display_info.monitor_range.min_vfreq == 0 ||
connector->display_info.monitor_range.max_vfreq == 0))
if (is_monitor_range_invalid(connector))
parse_edid_displayid_vrr(connector, edid);

if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
sink->sink_signal == SIGNAL_TYPE_EDP)) {
if (amdgpu_dm_connector->dc_link &&
amdgpu_dm_connector->dc_link->dpcd_caps.allow_invalid_MSA_timing_param) {
amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq;
amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq;
if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
freesync_capable = true;
}
/* DP & eDP excluding PCONs */
if ((sink->sink_signal == SIGNAL_TYPE_EDP ||
sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT) && !is_pcon) {
/*
* Many monitors expose AMD vsdb in CAE even for DP and their
* monitor ranges do not contain Range Limits Only flag
*/
if (is_monitor_range_invalid(connector))
monitor_range_from_vsdb(&connector->display_info, &vsdb_info);

parse_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
/* Use bigger range if found in AMD vsdb */
if (compare_ranges(connector, &vsdb_info))
monitor_range_from_vsdb(&connector->display_info, &vsdb_info);

if (vsdb_info.replay_mode) {
amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_info.replay_mode;
amdgpu_dm_connector->vsdb_info.amd_vsdb_version = vsdb_info.amd_vsdb_version;
amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
}
if (dpcd_caps.allow_invalid_MSA_timing_param)
freesync_capable = copy_range_to_amdgpu_connector(connector);

} else if (drm_edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
if (i >= 0 && vsdb_info.freesync_supported) {
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;
/* eDP */
if (edid)
parse_amd_vsdb_did(amdgpu_dm_connector, edid, &vsdb_did);

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;
if (vsdb_did.replay_mode) {
amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_did.replay_mode;
amdgpu_dm_connector->vsdb_info.amd_vsdb_version = vsdb_did.amd_vsdb_version;
amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
}
}

if (amdgpu_dm_connector->dc_link)
as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link);
/* HDMI */
} else if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
/* Prefer HDMI VRR */
if (hdmi_vrr.supported) {
amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_HDMI;
monitor_range_from_hdmi(&connector->display_info, &vsdb_info);
} else if (vsdb_info.freesync_supported)
monitor_range_from_vsdb(&connector->display_info, &vsdb_info);

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) {
freesync_capable = copy_range_to_amdgpu_connector(connector);

amdgpu_dm_connector->pack_sdp_v1_3 = true;
amdgpu_dm_connector->as_type = as_type;
/* DP -> HDMI PCON */
} else if (pcon_allowed) {
/* Prefer HDMI VRR */
if (hdmi_vrr.supported)
monitor_range_from_hdmi(&connector->display_info, &vsdb_info);
else if (vsdb_info.freesync_supported) {
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;
monitor_range_from_vsdb(&connector->display_info, &vsdb_info);
}

amdgpu_dm_connector->pack_sdp_v1_3 = true;
amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_PCON_ALLOWED;
freesync_capable = copy_range_to_amdgpu_connector(connector);
}

update:
Expand Down
Loading